diff options
40 files changed, 815 insertions, 167 deletions
diff --git a/package.json b/package.json index 81cec2b4f..3f2486656 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "lerna:rebuild": "run-s lerna:clean lerna:build", "lerna:publish": "run-s lerna:install lerna:rebuild script:publish", "lerna:publish:dry": "run-s lerna:install lerna:rebuild script:publish:dry", + "lerna:stage_docs": "lerna run docs:stage", "script:publish": "node ./packages/monorepo-scripts/lib/publish.js", "script:publish:dry": "IS_DRY_RUN=true yarn script:publish" }, diff --git a/packages/0x.js/README.md b/packages/0x.js/README.md index 46848cbdd..cfa353504 100644 --- a/packages/0x.js/README.md +++ b/packages/0x.js/README.md @@ -2,7 +2,7 @@ A TypeScript/Javascript library for interacting with the 0x protocol. -### Read the [Documentation](0xproject.com/docs/0xjs). +### Read the [Documentation](https://0xproject.com/docs/0xjs). ## Installation diff --git a/packages/abi-gen/src/index.ts b/packages/abi-gen/src/index.ts index 942bb12db..ecef33b16 100644 --- a/packages/abi-gen/src/index.ts +++ b/packages/abi-gen/src/index.ts @@ -1,7 +1,7 @@ #!/usr/bin/env node import { AbiDefinition, ConstructorAbi, EventAbi, MethodAbi } from '@0xproject/types'; -import { logUtils } from '@0xproject/utils'; +import { abiUtils, logUtils } from '@0xproject/utils'; import chalk from 'chalk'; import * as fs from 'fs'; import { sync as globSync } from 'glob'; @@ -12,7 +12,7 @@ import * as yargs from 'yargs'; import toSnakeCase = require('to-snake-case'); -import { ContextData, ContractsBackend, ParamKind } from './types'; +import { ContextData, ContractsBackend, Method, ParamKind } from './types'; import { utils } from './utils'; const ABI_TYPE_CONSTRUCTOR = 'constructor'; @@ -83,7 +83,6 @@ function writeOutputFile(name: string, renderedTsCode: string): void { Handlebars.registerHelper('parameterType', utils.solTypeToTsType.bind(utils, ParamKind.Input, args.backend)); Handlebars.registerHelper('returnType', utils.solTypeToTsType.bind(utils, ParamKind.Output, args.backend)); - if (args.partials) { registerPartials(args.partials); } @@ -126,11 +125,12 @@ for (const abiFileName of abiFileNames) { } const methodAbis = ABI.filter((abi: AbiDefinition) => abi.type === ABI_TYPE_METHOD) as MethodAbi[]; - const methodsData = _.map(methodAbis, methodAbi => { - _.map(methodAbi.inputs, (input, i: number) => { + const sanitizedMethodAbis = abiUtils.renameOverloadedMethods(methodAbis) as MethodAbi[]; + const methodsData = _.map(methodAbis, (methodAbi, methodAbiIndex: number) => { + _.forEach(methodAbi.inputs, (input, inputIndex: number) => { if (_.isEmpty(input.name)) { // Auto-generated getters don't have parameter names - input.name = `index_${i}`; + input.name = `index_${inputIndex}`; } }); // This will make templates simpler @@ -138,6 +138,8 @@ for (const abiFileName of abiFileNames) { ...methodAbi, singleReturnValue: methodAbi.outputs.length === 1, hasReturnValue: methodAbi.outputs.length !== 0, + tsName: sanitizedMethodAbis[methodAbiIndex].name, + functionSignature: abiUtils.getFunctionSignature(methodAbi), }; return methodData; }); diff --git a/packages/abi-gen/src/types.ts b/packages/abi-gen/src/types.ts index df5b1feaf..648281774 100644 --- a/packages/abi-gen/src/types.ts +++ b/packages/abi-gen/src/types.ts @@ -5,13 +5,6 @@ export enum ParamKind { Output = 'output', } -export enum AbiType { - Function = 'function', - Constructor = 'constructor', - Event = 'event', - Fallback = 'fallback', -} - export enum ContractsBackend { Web3 = 'web3', Ethers = 'ethers', @@ -20,6 +13,8 @@ export enum ContractsBackend { export interface Method extends MethodAbi { singleReturnValue: boolean; hasReturnValue: boolean; + tsName: string; + functionSignature: string; } export interface ContextData { diff --git a/packages/abi-gen/src/utils.ts b/packages/abi-gen/src/utils.ts index 755fbc71a..20b734959 100644 --- a/packages/abi-gen/src/utils.ts +++ b/packages/abi-gen/src/utils.ts @@ -1,9 +1,9 @@ -import { ConstructorAbi, DataItem } from '@0xproject/types'; +import { AbiType, ConstructorAbi, DataItem } from '@0xproject/types'; import * as fs from 'fs'; import * as _ from 'lodash'; import * as path from 'path'; -import { AbiType, ContractsBackend, ParamKind } from './types'; +import { ContractsBackend, ParamKind } from './types'; export const utils = { solTypeToTsType(paramKind: ParamKind, backend: ContractsBackend, solType: string, components?: DataItem[]): string { diff --git a/packages/base-contract/src/index.ts b/packages/base-contract/src/index.ts index bba686f8b..bfa99fac1 100644 --- a/packages/base-contract/src/index.ts +++ b/packages/base-contract/src/index.ts @@ -1,13 +1,26 @@ -import { ContractAbi, DataItem, Provider, TxData, TxDataPayable } from '@0xproject/types'; -import { BigNumber } from '@0xproject/utils'; +import { + AbiDefinition, + AbiType, + ContractAbi, + DataItem, + MethodAbi, + Provider, + TxData, + TxDataPayable, +} from '@0xproject/types'; +import { abiUtils, BigNumber } from '@0xproject/utils'; import { Web3Wrapper } from '@0xproject/web3-wrapper'; import * as ethersContracts from 'ethers-contracts'; import * as _ from 'lodash'; import { formatABIDataItem } from './utils'; +export interface EthersInterfaceByFunctionSignature { + [key: string]: ethersContracts.Interface; +} + export class BaseContract { - protected _ethersInterface: ethersContracts.Interface; + protected _ethersInterfacesByFunctionSignature: EthersInterfaceByFunctionSignature; protected _web3Wrapper: Web3Wrapper; public abi: ContractAbi; public address: string; @@ -49,10 +62,37 @@ export class BaseContract { } return txDataWithDefaults; } + protected _lookupEthersInterface(functionSignature: string): ethersContracts.Interface { + const ethersInterface = this._ethersInterfacesByFunctionSignature[functionSignature]; + if (_.isUndefined(ethersInterface)) { + throw new Error(`Failed to lookup method with function signature '${functionSignature}'`); + } + return ethersInterface; + } + protected _lookupAbi(functionSignature: string): MethodAbi { + const methodAbi = _.find(this.abi, (abiDefinition: AbiDefinition) => { + if (abiDefinition.type !== AbiType.Function) { + return false; + } + const abiFunctionSignature = abiUtils.getFunctionSignature(abiDefinition); + if (abiFunctionSignature === functionSignature) { + return true; + } + return false; + }) as MethodAbi; + return methodAbi; + } constructor(abi: ContractAbi, address: string, provider: Provider, defaults?: Partial<TxData>) { this._web3Wrapper = new Web3Wrapper(provider, defaults); this.abi = abi; this.address = address; - this._ethersInterface = new ethersContracts.Interface(abi); + const methodAbis = this.abi.filter( + (abiDefinition: AbiDefinition) => abiDefinition.type === AbiType.Function, + ) as MethodAbi[]; + this._ethersInterfacesByFunctionSignature = {}; + _.each(methodAbis, methodAbi => { + const functionSignature = abiUtils.getFunctionSignature(methodAbi); + this._ethersInterfacesByFunctionSignature[functionSignature] = new ethersContracts.Interface([methodAbi]); + }); } } diff --git a/packages/contract_templates/contract.handlebars b/packages/contract_templates/contract.handlebars index 3e3f87f10..472452d74 100644 --- a/packages/contract_templates/contract.handlebars +++ b/packages/contract_templates/contract.handlebars @@ -41,6 +41,6 @@ export class {{contractName}}Contract extends BaseContract { {{/each}} constructor(abi: ContractAbi, address: string, provider: Provider, defaults?: Partial<TxData>) { super(abi, address, provider, defaults); - classUtils.bindAll(this, ['_ethersInterface', 'address', 'abi', '_web3Wrapper']); + classUtils.bindAll(this, ['_ethersInterfacesByFunctionSignature', 'address', 'abi', '_web3Wrapper']); } } // tslint:disable:max-file-line-count diff --git a/packages/contract_templates/partials/callAsync.handlebars b/packages/contract_templates/partials/callAsync.handlebars index 8de69203e..a6f4abdf2 100644 --- a/packages/contract_templates/partials/callAsync.handlebars +++ b/packages/contract_templates/partials/callAsync.handlebars @@ -5,9 +5,9 @@ async callAsync( defaultBlock?: BlockParam, ): Promise<{{> return_type outputs=outputs}}> { const self = this as any as {{contractName}}Contract; - const inputAbi = (_.find(self.abi, {name: '{{this.name}}'}) as MethodAbi).inputs; + const inputAbi = self._lookupAbi('{{this.functionSignature}}').inputs; [{{> params inputs=inputs}}] = BaseContract._formatABIDataItemList(inputAbi, [{{> params inputs=inputs}}], BaseContract._bigNumberToString.bind(self)); - const encodedData = self._ethersInterface.functions.{{this.name}}( + const encodedData = self._lookupEthersInterface('{{this.functionSignature}}').functions.{{this.name}}( {{> params inputs=inputs}} ).data; const callDataWithDefaults = await self._applyDefaultsToTxDataAsync( diff --git a/packages/contract_templates/partials/tx.handlebars b/packages/contract_templates/partials/tx.handlebars index 41ba6d3f7..22fe0c597 100644 --- a/packages/contract_templates/partials/tx.handlebars +++ b/packages/contract_templates/partials/tx.handlebars @@ -1,4 +1,4 @@ -public {{this.name}} = { +public {{this.tsName}} = { async sendTransactionAsync( {{> typed_params inputs=inputs}} {{#this.payable}} @@ -9,17 +9,17 @@ public {{this.name}} = { {{/this.payable}} ): Promise<string> { const self = this as any as {{contractName}}Contract; - const inputAbi = (_.find(self.abi, {name: '{{this.name}}'}) as MethodAbi).inputs; + const inputAbi = self._lookupAbi('{{this.functionSignature}}').inputs; [{{> params inputs=inputs}}] = BaseContract._formatABIDataItemList(inputAbi, [{{> params inputs=inputs}}], BaseContract._bigNumberToString.bind(self)); - const encodedData = self._ethersInterface.functions.{{this.name}}( + const encodedData = self._lookupEthersInterface('{{this.functionSignature}}').functions.{{this.name}}( {{> params inputs=inputs}} - ).data + ).data; const txDataWithDefaults = await self._applyDefaultsToTxDataAsync( { ...txData, data: encodedData, }, - self.{{this.name}}.estimateGasAsync.bind( + self.{{this.tsName}}.estimateGasAsync.bind( self, {{> params inputs=inputs}} ), @@ -32,11 +32,11 @@ public {{this.name}} = { txData: Partial<TxData> = {}, ): Promise<number> { const self = this as any as {{contractName}}Contract; - const inputAbi = (_.find(self.abi, {name: '{{this.name}}'}) as MethodAbi).inputs; + const inputAbi = self._lookupAbi('{{this.functionSignature}}').inputs; [{{> params inputs=inputs}}] = BaseContract._formatABIDataItemList(inputAbi, [{{> params inputs=inputs}}], BaseContract._bigNumberToString.bind(this)); - const encodedData = self._ethersInterface.functions.{{this.name}}( + const encodedData = self._lookupEthersInterface('{{this.functionSignature}}').functions.{{this.name}}( {{> params inputs=inputs}} - ).data + ).data; const txDataWithDefaults = await self._applyDefaultsToTxDataAsync( { ...txData, @@ -50,11 +50,11 @@ public {{this.name}} = { {{> typed_params inputs=inputs}} ): string { const self = this as any as {{contractName}}Contract; - const inputAbi = (_.find(self.abi, {name: '{{this.name}}'}) as MethodAbi).inputs; + const inputAbi = self._lookupAbi('{{this.functionSignature}}').inputs; [{{> params inputs=inputs}}] = BaseContract._formatABIDataItemList(inputAbi, [{{> params inputs=inputs}}], BaseContract._bigNumberToString.bind(self)); - const abiEncodedTransactionData = self._ethersInterface.functions.{{this.name}}( + const abiEncodedTransactionData = self._lookupEthersInterface('{{this.name}}').functions.{{this.name}}( {{> params inputs=inputs}} - ).data + ).data; return abiEncodedTransactionData; }, {{> callAsync}} diff --git a/packages/contracts/package.json b/packages/contracts/package.json index 04073f4b7..392ed8a8f 100644 --- a/packages/contracts/package.json +++ b/packages/contracts/package.json @@ -16,7 +16,7 @@ "test:coverage": "SOLIDITY_COVERAGE=true run-s build run_mocha coverage:report:text coverage:report:lcov", "run_mocha": "mocha 'lib/test/**/*.js' --timeout 100000 --bail --exit", "compile:comment": "Yarn workspaces do not link binaries correctly so we need to reference them directly https://github.com/yarnpkg/yarn/issues/3846", - "compile": "node ../deployer/lib/src/cli.js compile --contracts ${npm_package_config_contracts} --contracts-dir src/contracts --artifacts-dir ../migrations/src/artifacts", + "compile": "node ../deployer/lib/src/cli.js compile --contracts ${npm_package_config_contracts} --contract-dirs src/contracts --artifacts-dir ../migrations/src/artifacts", "clean": "shx rm -rf ./lib", "generate_contract_wrappers": "node ../abi-gen/lib/index.js --abis ${npm_package_config_abis} --template ../contract_templates/contract.handlebars --partials '../contract_templates/partials/**/*.handlebars' --output src/contract_wrappers/generated --backend ethers && prettier --write 'src/contract_wrappers/generated/**.ts'", "lint": "tslint --project . 'migrations/**/*.ts' 'test/**/*.ts' 'util/**/*.ts' 'deploy/**/*.ts'", diff --git a/packages/deployer/README.md b/packages/deployer/README.md index d8b049bdf..ef0ddd59d 100644 --- a/packages/deployer/README.md +++ b/packages/deployer/README.md @@ -2,7 +2,7 @@ This repository contains a CLI tool that facilitates compiling and deployment of smart contracts. -### Read the [Documentation](0xproject.com/docs/deployer). +### Read the [Documentation](https://0xproject.com/docs/deployer). ## Installation diff --git a/packages/deployer/package.json b/packages/deployer/package.json index ad4ff30df..2c8ad4943 100644 --- a/packages/deployer/package.json +++ b/packages/deployer/package.json @@ -54,6 +54,7 @@ "@types/semver": "^5.5.0", "@types/yargs": "^11.0.0", "chai": "^4.0.1", + "chai-as-promised": "^7.1.0", "copyfiles": "^1.2.0", "dirty-chai": "^2.0.1", "mocha": "^4.0.1", diff --git a/packages/deployer/src/cli.ts b/packages/deployer/src/cli.ts index f1cf56416..7b32187c4 100644 --- a/packages/deployer/src/cli.ts +++ b/packages/deployer/src/cli.ts @@ -11,7 +11,7 @@ import * as yargs from 'yargs'; import { commands } from './commands'; import { constants } from './utils/constants'; import { consoleReporter } from './utils/error_reporter'; -import { CliOptions, CompilerOptions, DeployerOptions } from './utils/types'; +import { CliOptions, CompilerOptions, ContractDirectory, DeployerOptions } from './utils/types'; const DEFAULT_OPTIMIZER_ENABLED = false; const DEFAULT_CONTRACTS_DIR = path.resolve('src/contracts'); @@ -27,7 +27,7 @@ const DEFAULT_CONTRACTS_LIST = '*'; */ async function onCompileCommandAsync(argv: CliOptions): Promise<void> { const opts: CompilerOptions = { - contractsDir: argv.contractsDir, + contractDirs: getContractDirectoriesFromList(argv.contractDirs), networkId: argv.networkId, optimizerEnabled: argv.shouldOptimize, artifactsDir: argv.artifactsDir, @@ -45,7 +45,7 @@ async function onDeployCommandAsync(argv: CliOptions): Promise<void> { const web3Wrapper = new Web3Wrapper(provider); const networkId = await web3Wrapper.getNetworkIdAsync(); const compilerOpts: CompilerOptions = { - contractsDir: argv.contractsDir, + contractDirs: getContractDirectoriesFromList(argv.contractDirs), networkId, optimizerEnabled: argv.shouldOptimize, artifactsDir: argv.artifactsDir, @@ -69,6 +69,29 @@ async function onDeployCommandAsync(argv: CliOptions): Promise<void> { } /** * Creates a set of contracts to compile. + * @param contractDirectoriesList Comma separated list of contract directories + * @return Set of contract directories + */ +function getContractDirectoriesFromList(contractDirectoriesList: string): Set<ContractDirectory> { + const directories = new Set(); + const possiblyNamespacedDirectories = contractDirectoriesList.split(','); + _.forEach(possiblyNamespacedDirectories, namespacedDirectory => { + const directoryComponents = namespacedDirectory.split(':'); + if (directoryComponents.length === 1) { + const directory = { namespace: '', path: directoryComponents[0] }; + directories.add(directory); + } else if (directoryComponents.length === 2) { + const directory = { namespace: directoryComponents[0], path: directoryComponents[1] }; + directories.add(directory); + } else { + throw new Error(`Unable to parse contracts directory: '${namespacedDirectory}'`); + } + }); + + return directories; +} +/** + * Creates a set of contracts to compile. * @param contracts Comma separated list of contracts to compile */ function getContractsSetFromList(contracts: string): Set<string> { @@ -78,8 +101,7 @@ function getContractsSetFromList(contracts: string): Set<string> { } const contractsArray = contracts.split(','); _.forEach(contractsArray, contractName => { - const fileName = `${contractName}${constants.SOLIDITY_FILE_EXTENSION}`; - specifiedContracts.add(fileName); + specifiedContracts.add(contractName); }); return specifiedContracts; } @@ -104,10 +126,11 @@ function deployCommandBuilder(yargsInstance: any) { (() => { const identityCommandBuilder = _.identity; return yargs - .option('contracts-dir', { + .option('contract-dirs', { type: 'string', default: DEFAULT_CONTRACTS_DIR, - description: 'path of contracts directory to compile', + description: + "comma separated list of contract directories.\nTo avoid filename clashes, directories should be prefixed with a namespace as follows: 'namespace:/path/to/dir'.", }) .option('network-id', { type: 'number', diff --git a/packages/deployer/src/compiler.ts b/packages/deployer/src/compiler.ts index ba360cb57..e3ecc6c72 100644 --- a/packages/deployer/src/compiler.ts +++ b/packages/deployer/src/compiler.ts @@ -1,4 +1,4 @@ -import { ContractAbi } from '@0xproject/types'; +import { AbiType, ContractAbi, MethodAbi } from '@0xproject/types'; import { logUtils, promisify } from '@0xproject/utils'; import * as ethUtil from 'ethereumjs-util'; import * as fs from 'fs'; @@ -11,6 +11,8 @@ import solc = require('solc'); import { binPaths } from './solc/bin_paths'; import { + constructContractId, + constructUniqueSourceFileId, createDirIfDoesNotExistAsync, findImportIfExist, getContractArtifactIfExistsAsync, @@ -23,11 +25,14 @@ import { fsWrapper } from './utils/fs_wrapper'; import { CompilerOptions, ContractArtifact, + ContractDirectory, + ContractIdToSourceFileId, ContractNetworkData, ContractNetworks, - ContractSourceData, + ContractSourceDataByFileId, ContractSources, ContractSpecificSourceData, + FunctionNameToSeenCount, } from './utils/types'; import { utils } from './utils/utils'; @@ -39,20 +44,22 @@ const SOLC_BIN_DIR = path.join(__dirname, '..', '..', 'solc_bin'); * to artifact files. */ export class Compiler { - private _contractsDir: string; + private _contractDirs: Set<ContractDirectory>; private _networkId: number; private _optimizerEnabled: boolean; private _artifactsDir: string; // This get's set in the beggining of `compileAsync` function. It's not called from a constructor, but it's the only public method of that class and could as well be. private _contractSources!: ContractSources; private _specifiedContracts: Set<string> = new Set(); - private _contractSourceData: ContractSourceData = {}; + private _contractSourceDataByFileId: ContractSourceDataByFileId = {}; + /** * Recursively retrieves Solidity source code from directory. * @param dirPath Directory to search. - * @return Mapping of contract fileName to contract source. + * @param contractBaseDir Base contracts directory of search tree. + * @return Mapping of sourceFilePath to the contract source. */ - private static async _getContractSourcesAsync(dirPath: string): Promise<ContractSources> { + private static async _getContractSourcesAsync(dirPath: string, contractBaseDir: string): Promise<ContractSources> { let dirContents: string[] = []; try { dirContents = await fsWrapper.readdirAsync(dirPath); @@ -68,14 +75,18 @@ export class Compiler { encoding: 'utf8', }; const source = await fsWrapper.readFileAsync(contentPath, opts); - sources[fileName] = source; - logUtils.log(`Reading ${fileName} source...`); + if (!_.startsWith(contentPath, contractBaseDir)) { + throw new Error(`Expected content path '${contentPath}' to begin with '${contractBaseDir}'`); + } + const sourceFilePath = contentPath.slice(contractBaseDir.length); + sources[sourceFilePath] = source; + logUtils.log(`Reading ${sourceFilePath} source...`); } catch (err) { logUtils.log(`Could not find file at ${contentPath}`); } } else { try { - const nestedSources = await Compiler._getContractSourcesAsync(contentPath); + const nestedSources = await Compiler._getContractSourcesAsync(contentPath, contractBaseDir); sources = { ...sources, ...nestedSources, @@ -93,7 +104,7 @@ export class Compiler { * @return An instance of the Compiler class. */ constructor(opts: CompilerOptions) { - this._contractsDir = opts.contractsDir; + this._contractDirs = opts.contractDirs; this._networkId = opts.networkId; this._optimizerEnabled = opts.optimizerEnabled; this._artifactsDir = opts.artifactsDir; @@ -105,25 +116,49 @@ export class Compiler { public async compileAsync(): Promise<void> { await createDirIfDoesNotExistAsync(this._artifactsDir); await createDirIfDoesNotExistAsync(SOLC_BIN_DIR); - this._contractSources = await Compiler._getContractSourcesAsync(this._contractsDir); + this._contractSources = {}; + const contractIdToSourceFileId: ContractIdToSourceFileId = {}; + const contractDirs = Array.from(this._contractDirs.values()); + for (const contractDir of contractDirs) { + const sources = await Compiler._getContractSourcesAsync(contractDir.path, contractDir.path); + _.forIn(sources, (source, sourceFilePath) => { + const sourceFileId = constructUniqueSourceFileId(contractDir.namespace, sourceFilePath); + // Record the file's source and data + if (!_.isUndefined(this._contractSources[sourceFileId])) { + throw new Error(`Found duplicate source files with ID '${sourceFileId}'`); + } + this._contractSources[sourceFileId] = source; + // Create a mapping between the contract id and its source file id + const contractId = constructContractId(contractDir.namespace, sourceFilePath); + if (!_.isUndefined(contractIdToSourceFileId[contractId])) { + throw new Error(`Found duplicate contract with ID '${contractId}'`); + } + contractIdToSourceFileId[contractId] = sourceFileId; + }); + } _.forIn(this._contractSources, this._setContractSpecificSourceData.bind(this)); - const fileNames = this._specifiedContracts.has(ALL_CONTRACTS_IDENTIFIER) - ? _.keys(this._contractSources) + const specifiedContractIds = this._specifiedContracts.has(ALL_CONTRACTS_IDENTIFIER) + ? _.keys(contractIdToSourceFileId) : Array.from(this._specifiedContracts.values()); - for (const fileName of fileNames) { - await this._compileContractAsync(fileName); - } + await Promise.all( + _.map(specifiedContractIds, async contractId => + this._compileContractAsync(contractIdToSourceFileId[contractId]), + ), + ); } /** * Compiles contract and saves artifact to artifactsDir. - * @param fileName Name of contract with '.sol' extension. + * @param sourceFileId Unique ID of the source file. */ - private async _compileContractAsync(fileName: string): Promise<void> { + private async _compileContractAsync(sourceFileId: string): Promise<void> { if (_.isUndefined(this._contractSources)) { throw new Error('Contract sources not yet initialized'); } - const contractSpecificSourceData = this._contractSourceData[fileName]; - const currentArtifactIfExists = await getContractArtifactIfExistsAsync(this._artifactsDir, fileName); + if (_.isUndefined(this._contractSourceDataByFileId[sourceFileId])) { + throw new Error(`Contract source for ${sourceFileId} not yet initialized`); + } + const contractSpecificSourceData = this._contractSourceDataByFileId[sourceFileId]; + const currentArtifactIfExists = await getContractArtifactIfExistsAsync(this._artifactsDir, sourceFileId); const sourceHash = `0x${contractSpecificSourceData.sourceHash.toString('hex')}`; const sourceTreeHash = `0x${contractSpecificSourceData.sourceTreeHash.toString('hex')}`; @@ -162,16 +197,17 @@ export class Compiler { } const solcInstance = solc.setupMethods(requireFromString(solcjs, compilerBinFilename)); - logUtils.log(`Compiling ${fileName} with Solidity v${solcVersion}...`); - const source = this._contractSources[fileName]; + logUtils.log(`Compiling ${sourceFileId} with Solidity v${solcVersion}...`); + const source = this._contractSources[sourceFileId]; const input = { - [fileName]: source, + [sourceFileId]: source, }; const sourcesToCompile = { sources: input, }; + const compiled = solcInstance.compile(sourcesToCompile, Number(this._optimizerEnabled), importPath => - findImportIfExist(this._contractSources, importPath), + findImportIfExist(this._contractSources, sourceFileId, importPath), ); if (!_.isUndefined(compiled.errors)) { @@ -193,11 +229,11 @@ export class Compiler { }); } } - const contractName = path.basename(fileName, constants.SOLIDITY_FILE_EXTENSION); - const contractIdentifier = `${fileName}:${contractName}`; + const contractName = path.basename(sourceFileId, constants.SOLIDITY_FILE_EXTENSION); + const contractIdentifier = `${sourceFileId}:${contractName}`; if (_.isUndefined(compiled.contracts[contractIdentifier])) { throw new Error( - `Contract ${contractName} not found in ${fileName}. Please make sure your contract has the same name as it's file name`, + `Contract ${contractName} not found in ${sourceFileId}. Please make sure your contract has the same name as it's file name`, ); } const abi: ContractAbi = JSON.parse(compiled.contracts[contractIdentifier].interface); @@ -207,6 +243,7 @@ export class Compiler { const sourceMapRuntime = compiled.contracts[contractIdentifier].srcmapRuntime; const sources = _.keys(compiled.sources); const updated_at = Date.now(); + const contractNetworkData: ContractNetworkData = { solc_version: solcVersion, keccak256: sourceHash, @@ -243,28 +280,30 @@ export class Compiler { const artifactString = utils.stringifyWithFormatting(newArtifact); const currentArtifactPath = `${this._artifactsDir}/${contractName}.json`; await fsWrapper.writeFileAsync(currentArtifactPath, artifactString); - logUtils.log(`${fileName} artifact saved!`); + logUtils.log(`${sourceFileId} artifact saved!`); } /** * Gets contract dependendencies and keccak256 hash from source. * @param source Source code of contract. + * @param fileId FileId of the contract source file. * @return Object with contract dependencies and keccak256 hash of source. */ - private _setContractSpecificSourceData(source: string, fileName: string): void { - if (!_.isUndefined(this._contractSourceData[fileName])) { + private _setContractSpecificSourceData(source: string, fileId: string): void { + if (!_.isUndefined(this._contractSourceDataByFileId[fileId])) { return; } const sourceHash = ethUtil.sha3(source); const solcVersionRange = parseSolidityVersionRange(source); - const dependencies = parseDependencies(source); - const sourceTreeHash = this._getSourceTreeHash(fileName, sourceHash, dependencies); - this._contractSourceData[fileName] = { + const dependencies = parseDependencies(source, fileId); + const sourceTreeHash = this._getSourceTreeHash(fileId, sourceHash, dependencies); + this._contractSourceDataByFileId[fileId] = { dependencies, solcVersionRange, sourceHash, sourceTreeHash, }; } + /** * Gets the source tree hash for a file and its dependencies. * @param fileName Name of contract file. @@ -276,7 +315,7 @@ export class Compiler { const dependencySourceTreeHashes = _.map(dependencies, dependency => { const source = this._contractSources[dependency]; this._setContractSpecificSourceData(source, dependency); - const sourceData = this._contractSourceData[dependency]; + const sourceData = this._contractSourceDataByFileId[dependency]; return this._getSourceTreeHash(dependency, sourceData.sourceHash, sourceData.dependencies); }); const sourceTreeHashesBuffer = Buffer.concat([sourceHash, ...dependencySourceTreeHashes]); diff --git a/packages/deployer/src/utils/compiler.ts b/packages/deployer/src/utils/compiler.ts index d5137d394..600495693 100644 --- a/packages/deployer/src/utils/compiler.ts +++ b/packages/deployer/src/utils/compiler.ts @@ -1,3 +1,4 @@ +import { AbiType, ContractAbi, MethodAbi } from '@0xproject/types'; import { logUtils } from '@0xproject/utils'; import * as _ from 'lodash'; import * as path from 'path'; @@ -5,9 +6,49 @@ import * as solc from 'solc'; import { constants } from './constants'; import { fsWrapper } from './fs_wrapper'; -import { ContractArtifact, ContractSources } from './types'; +import { ContractArtifact, ContractSources, FunctionNameToSeenCount } from './types'; /** + * Constructs a system-wide unique identifier for a source file. + * @param directoryNamespace Namespace of the source file's root contract directory. + * @param sourceFilePath Path to a source file, relative to contractBaseDir. + * @return sourceFileId A system-wide unique identifier for the source file. + */ +export function constructUniqueSourceFileId(directoryNamespace: string, sourceFilePath: string): string { + const namespacePrefix = !_.isEmpty(directoryNamespace) ? `/${directoryNamespace}` : ''; + const sourceFilePathNoLeadingSlash = sourceFilePath.replace(/^\/+/g, ''); + const sourceFileId = `${namespacePrefix}/${sourceFilePathNoLeadingSlash}`; + return sourceFileId; +} +/** + * Constructs a system-wide unique identifier for a dependency file. + * @param dependencyFilePath Path from a sourceFile to a dependency. + * @param contractBaseDir Base contracts directory of search tree. + * @return sourceFileId A system-wide unique identifier for the source file. + */ +export function constructDependencyFileId(dependencyFilePath: string, sourceFilePath: string): string { + if (_.startsWith(dependencyFilePath, '/')) { + // Path of the form /namespace/path/to/dependency.sol + return dependencyFilePath; + } else { + // Dependency is relative to the source file: ./dependency.sol, ../../some/path/dependency.sol, etc. + // Join the two paths to construct a valid source file id: /namespace/path/to/dependency.sol + return path.join(path.dirname(sourceFilePath), dependencyFilePath); + } +} +/** + * Constructs a system-wide unique identifier for a contract. + * @param directoryNamespace Namespace of the source file's root contract directory. + * @param sourceFilePath Path to a source file, relative to contractBaseDir. + * @return sourceFileId A system-wide unique identifier for contract. + */ +export function constructContractId(directoryNamespace: string, sourceFilePath: string): string { + const namespacePrefix = !_.isEmpty(directoryNamespace) ? `${directoryNamespace}:` : ''; + const sourceFileName = path.basename(sourceFilePath, constants.SOLIDITY_FILE_EXTENSION); + const contractId = `${namespacePrefix}${sourceFileName}`; + return contractId; +} +/** * 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. @@ -82,9 +123,10 @@ export function getNormalizedErrMsg(errMsg: string): string { /** * Parses the contract source code and extracts the dendencies * @param source Contract source code + * @param sourceFilePath File path of the source code. * @return List of dependendencies */ -export function parseDependencies(source: string): string[] { +export function parseDependencies(source: string, sourceFileId: 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 @@ -95,8 +137,8 @@ export function parseDependencies(source: string): string[] { const dependencyMatch = line.match(DEPENDENCY_PATH_REGEX); if (!_.isNull(dependencyMatch)) { const dependencyPath = dependencyMatch[1]; - const basenName = path.basename(dependencyPath); - dependencies.push(basenName); + const dependencyId = constructDependencyFileId(dependencyPath, sourceFileId); + dependencies.push(dependencyId); } } }); @@ -107,14 +149,19 @@ export function parseDependencies(source: string): string[] { * 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. + * @param sourceFileId ID of the source file. + * @param importPath Path of dependency source file. * @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]; +export function findImportIfExist( + contractSources: ContractSources, + sourceFileId: string, + importPath: string, +): solc.ImportContents { + const dependencyFileId = constructDependencyFileId(importPath, sourceFileId); + const source = contractSources[dependencyFileId]; if (_.isUndefined(source)) { - throw new Error(`Contract source not found for ${fileName}`); + throw new Error(`Contract source not found for ${dependencyFileId}`); } const importContents: solc.ImportContents = { contents: source, diff --git a/packages/deployer/src/utils/contract.ts b/packages/deployer/src/utils/contract.ts index 9b7baac11..e8dd5218a 100644 --- a/packages/deployer/src/utils/contract.ts +++ b/packages/deployer/src/utils/contract.ts @@ -1,11 +1,9 @@ import { schemas, SchemaValidator } from '@0xproject/json-schemas'; -import { ContractAbi, EventAbi, FunctionAbi, MethodAbi, TxData } from '@0xproject/types'; +import { AbiType, ContractAbi, EventAbi, FunctionAbi, MethodAbi, TxData } from '@0xproject/types'; import { promisify } from '@0xproject/utils'; import * as _ from 'lodash'; import * as Web3 from 'web3'; -import { AbiType } from './types'; - export class Contract implements Web3.ContractInstance { public address: string; public abi: ContractAbi; diff --git a/packages/deployer/src/utils/encoder.ts b/packages/deployer/src/utils/encoder.ts index 4f62662e1..806efbbca 100644 --- a/packages/deployer/src/utils/encoder.ts +++ b/packages/deployer/src/utils/encoder.ts @@ -1,9 +1,7 @@ -import { AbiDefinition, ContractAbi, DataItem } from '@0xproject/types'; +import { AbiDefinition, AbiType, ContractAbi, DataItem } from '@0xproject/types'; import * as _ from 'lodash'; import * as web3Abi from 'web3-eth-abi'; -import { AbiType } from './types'; - export const encoder = { encodeConstructorArgsFromAbi(args: any[], abi: ContractAbi): string { const constructorTypes: string[] = []; diff --git a/packages/deployer/src/utils/types.ts b/packages/deployer/src/utils/types.ts index 7d131f5ce..1a866b873 100644 --- a/packages/deployer/src/utils/types.ts +++ b/packages/deployer/src/utils/types.ts @@ -18,6 +18,11 @@ export interface ContractNetworks { [key: number]: ContractNetworkData; } +export interface ContractDirectory { + path: string; + namespace: string; +} + export interface ContractNetworkData { solc_version: string; optimizer_enabled: boolean; @@ -40,7 +45,7 @@ export interface SolcErrors { export interface CliOptions extends yargs.Arguments { artifactsDir: string; - contractsDir: string; + contractDirs: string; jsonrpcUrl: string; networkId: number; shouldOptimize: boolean; @@ -51,7 +56,7 @@ export interface CliOptions extends yargs.Arguments { } export interface CompilerOptions { - contractsDir: string; + contractDirs: Set<ContractDirectory>; networkId: number; optimizerEnabled: boolean; artifactsDir: string; @@ -78,7 +83,11 @@ export interface ContractSources { [key: string]: string; } -export interface ContractSourceData { +export interface ContractIdToSourceFileId { + [key: string]: string; +} + +export interface ContractSourceDataByFileId { [key: string]: ContractSpecificSourceData; } @@ -98,4 +107,8 @@ export interface Token { swarmHash: string; } +export interface FunctionNameToSeenCount { + [key: string]: number; +} + export type DoneCallback = (err?: Error) => void; diff --git a/packages/deployer/test/compiler_test.ts b/packages/deployer/test/compiler_test.ts index b03ae7935..817a3b3f9 100644 --- a/packages/deployer/test/compiler_test.ts +++ b/packages/deployer/test/compiler_test.ts @@ -3,7 +3,13 @@ import 'mocha'; import { Compiler } from '../src/compiler'; import { fsWrapper } from '../src/utils/fs_wrapper'; -import { CompilerOptions, ContractArtifact, ContractNetworkData, DoneCallback } from '../src/utils/types'; +import { + CompilerOptions, + ContractArtifact, + ContractDirectory, + ContractNetworkData, + DoneCallback, +} from '../src/utils/types'; import { exchange_binary } from './fixtures/exchange_bin'; import { constants } from './util/constants'; @@ -13,11 +19,15 @@ const expect = chai.expect; describe('#Compiler', function() { this.timeout(constants.timeoutMs); const artifactsDir = `${__dirname}/fixtures/artifacts`; - const contractsDir = `${__dirname}/fixtures/contracts`; + const mainContractDir: ContractDirectory = { path: `${__dirname}/fixtures/contracts/main`, namespace: 'main' }; + const baseContractDir: ContractDirectory = { path: `${__dirname}/fixtures/contracts/base`, namespace: 'base' }; + const contractDirs: Set<ContractDirectory> = new Set(); + contractDirs.add(mainContractDir); + contractDirs.add(baseContractDir); const exchangeArtifactPath = `${artifactsDir}/Exchange.json`; const compilerOpts: CompilerOptions = { artifactsDir, - contractsDir, + contractDirs, networkId: constants.networkId, optimizerEnabled: constants.optimizerEnabled, specifiedContracts: new Set(constants.specifiedContracts), diff --git a/packages/deployer/test/compiler_utils_test.ts b/packages/deployer/test/compiler_utils_test.ts index 246304858..5377d3308 100644 --- a/packages/deployer/test/compiler_utils_test.ts +++ b/packages/deployer/test/compiler_utils_test.ts @@ -47,28 +47,34 @@ describe('Compiler utils', () => { }); describe('#parseDependencies', () => { it('correctly parses Exchange dependencies', async () => { - const exchangeSource = await fsWrapper.readFileAsync(`${__dirname}/fixtures/contracts/Exchange.sol`, { + const exchangeSource = await fsWrapper.readFileAsync(`${__dirname}/fixtures/contracts/main/Exchange.sol`, { encoding: 'utf8', }); - expect(parseDependencies(exchangeSource)).to.be.deep.equal([ - 'TokenTransferProxy.sol', - 'Token.sol', - 'SafeMath.sol', + const sourceFileId = '/main/Exchange.sol'; + expect(parseDependencies(exchangeSource, sourceFileId)).to.be.deep.equal([ + '/main/TokenTransferProxy.sol', + '/base/Token.sol', + '/base/SafeMath.sol', ]); }); it('correctly parses TokenTransferProxy dependencies', async () => { const exchangeSource = await fsWrapper.readFileAsync( - `${__dirname}/fixtures/contracts/TokenTransferProxy.sol`, + `${__dirname}/fixtures/contracts/main/TokenTransferProxy.sol`, { encoding: 'utf8', }, ); - expect(parseDependencies(exchangeSource)).to.be.deep.equal(['Token.sol', 'Ownable.sol']); + const sourceFileId = '/main/TokenTransferProxy.sol'; + expect(parseDependencies(exchangeSource, sourceFileId)).to.be.deep.equal([ + '/base/Token.sol', + '/base/Ownable.sol', + ]); }); // TODO: For now that doesn't work. This will work after we switch to a grammar-based parser it.skip('correctly parses commented out dependencies', async () => { const contractWithCommentedOutDependencies = `// import "./TokenTransferProxy.sol";`; - expect(parseDependencies(contractWithCommentedOutDependencies)).to.be.deep.equal([]); + const sourceFileId = '/main/TokenTransferProxy.sol'; + expect(parseDependencies(contractWithCommentedOutDependencies, sourceFileId)).to.be.deep.equal([]); }); }); }); diff --git a/packages/deployer/test/deployer_test.ts b/packages/deployer/test/deployer_test.ts index 238624220..a213932f9 100644 --- a/packages/deployer/test/deployer_test.ts +++ b/packages/deployer/test/deployer_test.ts @@ -4,7 +4,13 @@ import 'mocha'; import { Compiler } from '../src/compiler'; import { Deployer } from '../src/deployer'; import { fsWrapper } from '../src/utils/fs_wrapper'; -import { CompilerOptions, ContractArtifact, ContractNetworkData, DoneCallback } from '../src/utils/types'; +import { + CompilerOptions, + ContractArtifact, + ContractDirectory, + ContractNetworkData, + DoneCallback, +} from '../src/utils/types'; import { constructor_args, exchange_binary } from './fixtures/exchange_bin'; import { constants } from './util/constants'; @@ -14,11 +20,15 @@ const expect = chai.expect; describe('#Deployer', () => { const artifactsDir = `${__dirname}/fixtures/artifacts`; - const contractsDir = `${__dirname}/fixtures/contracts`; const exchangeArtifactPath = `${artifactsDir}/Exchange.json`; + const mainContractDir: ContractDirectory = { path: `${__dirname}/fixtures/contracts/main`, namespace: '' }; + const baseContractDir: ContractDirectory = { path: `${__dirname}/fixtures/contracts/base`, namespace: 'base' }; + const contractDirs: Set<ContractDirectory> = new Set(); + contractDirs.add(mainContractDir); + contractDirs.add(baseContractDir); const compilerOpts: CompilerOptions = { artifactsDir, - contractsDir, + contractDirs, networkId: constants.networkId, optimizerEnabled: constants.optimizerEnabled, specifiedContracts: new Set(constants.specifiedContracts), diff --git a/packages/deployer/test/fixtures/contracts/Exchange.sol b/packages/deployer/test/fixtures/contracts/main/Exchange.sol index 1b6819700..ea9ca3afa 100644 --- a/packages/deployer/test/fixtures/contracts/Exchange.sol +++ b/packages/deployer/test/fixtures/contracts/main/Exchange.sol @@ -1,6 +1,6 @@ /* - Copyright 2017 ZeroEx Intl. + Copyright 2018 ZeroEx Intl. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -19,8 +19,8 @@ pragma solidity 0.4.14; import "./TokenTransferProxy.sol"; -import "./base/Token.sol"; -import "./base/SafeMath.sol"; +import "/base/Token.sol"; +import "/base/SafeMath.sol"; /// @title Exchange - Facilitates exchange of ERC20 tokens. /// @author Amir Bandeali - <amir@0xProject.com>, Will Warren - <will@0xProject.com> diff --git a/packages/deployer/test/fixtures/contracts/TokenTransferProxy.sol b/packages/deployer/test/fixtures/contracts/main/TokenTransferProxy.sol index 90c8e7d66..99d16cb57 100644 --- a/packages/deployer/test/fixtures/contracts/TokenTransferProxy.sol +++ b/packages/deployer/test/fixtures/contracts/main/TokenTransferProxy.sol @@ -1,6 +1,6 @@ /* - Copyright 2017 ZeroEx Intl. + Copyright 2018 ZeroEx Intl. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -18,8 +18,8 @@ pragma solidity 0.4.14; -import "./base/Token.sol"; -import "./base/Ownable.sol"; +import "/base/Token.sol"; +import "/base/Ownable.sol"; /// @title TokenTransferProxy - Transfers tokens on behalf of contracts that have been approved via decentralized governance. /// @author Amir Bandeali - <amir@0xProject.com>, Will Warren - <will@0xProject.com> diff --git a/packages/json-schemas/README.md b/packages/json-schemas/README.md index e8cece63b..ffa8e947a 100644 --- a/packages/json-schemas/README.md +++ b/packages/json-schemas/README.md @@ -2,7 +2,7 @@ Contains 0x-related json schemas -### Read the [Documentation](0xproject.com/docs/json-schemas). +### Read the [Documentation](https://0xproject.com/docs/json-schemas). ## Installation diff --git a/packages/metacoin/artifacts/Metacoin.json b/packages/metacoin/artifacts/Metacoin.json index 46c3ee71c..69ec22cac 100644 --- a/packages/metacoin/artifacts/Metacoin.json +++ b/packages/metacoin/artifacts/Metacoin.json @@ -3,11 +3,50 @@ "networks": { "50": { "solc_version": "0.4.21", - "keccak256": "0x2c3aa2e9dbef58abf57cecc148464d0852a83d7f30bbd2066f2a13b8bd3b1dd0", - "source_tree_hash": "0x2c3aa2e9dbef58abf57cecc148464d0852a83d7f30bbd2066f2a13b8bd3b1dd0", + "keccak256": "0x85fb29ea6c21adcf07f754b2ad06482dd6fcd62d31935e36041b4d064c6a038e", + "source_tree_hash": "0x85fb29ea6c21adcf07f754b2ad06482dd6fcd62d31935e36041b4d064c6a038e", "optimizer_enabled": false, "abi": [ { + "constant": false, + "inputs": [ + { + "components": [ + { + "components": [ + { + "name": "to", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "transferData", + "type": "tuple" + }, + { + "name": "callback", + "type": "uint32" + } + ], + "name": "nestedTransferData", + "type": "tuple" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "int256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { "constant": true, "inputs": [ { @@ -56,6 +95,39 @@ "type": "function" }, { + "constant": false, + "inputs": [ + { + "components": [ + { + "name": "to", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "transferData", + "type": "tuple" + }, + { + "name": "callback", + "type": "uint32" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "int256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { "inputs": [], "payable": false, "stateMutability": "nonpayable", @@ -84,15 +156,14 @@ "type": "event" } ], - "bytecode": - "0x6060604052341561000f57600080fd5b6127106000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550610406806100636000396000f30060606040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806327e235e3146100515780632bd14bb914610087575b600080fd5b341561005c57600080fd5b610071600461006c9036906102b9565b6100bd565b60405161007e9190610344565b60405180910390f35b341561009257600080fd5b6100a760046100a29036906102e2565b6100d5565b6040516100b49190610329565b60405180910390f35b60006020528060005260406000206000915090505481565b600081602001516000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054101561012a5760009050610240565b81602001516000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825403925050819055508160200151600080846000015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540192505081905550816000015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84602001516040516102339190610344565b60405180910390a3600190505b919050565b600061025182356103a2565b905092915050565b60006040828403121561026b57600080fd5b610275604061035f565b9050600061028584828501610245565b6000830152506020610299848285016102a5565b60208301525092915050565b60006102b182356103c2565b905092915050565b6000602082840312156102cb57600080fd5b60006102d984828501610245565b91505092915050565b6000604082840312156102f457600080fd5b600061030284828501610259565b91505092915050565b6103148161038c565b82525050565b61032381610398565b82525050565b600060208201905061033e600083018461030b565b92915050565b6000602082019050610359600083018461031a565b92915050565b6000604051905081810181811067ffffffffffffffff8211171561038257600080fd5b8060405250919050565b60008115159050919050565b6000819050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60008190509190505600a265627a7a72305820d15828219194e8ddaa624e10f9c8823c05268d79753b4c60ef401fb4fe5f09dc6c6578706572696d656e74616cf50037", - "runtime_bytecode": - "0x60606040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806327e235e3146100515780632bd14bb914610087575b600080fd5b341561005c57600080fd5b610071600461006c9036906102b9565b6100bd565b60405161007e9190610344565b60405180910390f35b341561009257600080fd5b6100a760046100a29036906102e2565b6100d5565b6040516100b49190610329565b60405180910390f35b60006020528060005260406000206000915090505481565b600081602001516000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054101561012a5760009050610240565b81602001516000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825403925050819055508160200151600080846000015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540192505081905550816000015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84602001516040516102339190610344565b60405180910390a3600190505b919050565b600061025182356103a2565b905092915050565b60006040828403121561026b57600080fd5b610275604061035f565b9050600061028584828501610245565b6000830152506020610299848285016102a5565b60208301525092915050565b60006102b182356103c2565b905092915050565b6000602082840312156102cb57600080fd5b60006102d984828501610245565b91505092915050565b6000604082840312156102f457600080fd5b600061030284828501610259565b91505092915050565b6103148161038c565b82525050565b61032381610398565b82525050565b600060208201905061033e600083018461030b565b92915050565b6000602082019050610359600083018461031a565b92915050565b6000604051905081810181811067ffffffffffffffff8211171561038257600080fd5b8060405250919050565b60008115159050919050565b6000819050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60008190509190505600a265627a7a72305820d15828219194e8ddaa624e10f9c8823c05268d79753b4c60ef401fb4fe5f09dc6c6578706572696d656e74616cf50037", - "updated_at": 1522318279735, - "source_map": "60:662:0:-;;;290:72;;;;;;;;350:5;327:8;:20;336:10;327:20;;;;;;;;;;;;;;;:28;;;;60:662;;;;;;", - "source_map_runtime": - "60:662:0:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;84:41;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;368:352;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;84:41;;;;;;;;;;;;;;;;;:::o;368:352::-;429:12;480;:19;;;457:8;:20;466:10;457:20;;;;;;;;;;;;;;;;:42;453:60;;;508:5;501:12;;;;453:60;547:12;:19;;;523:8;:20;532:10;523:20;;;;;;;;;;;;;;;;:43;;;;;;;;;;;605:12;:19;;;576:8;:25;585:12;:15;;;576:25;;;;;;;;;;;;;;;;:48;;;;;;;;;;;655:12;:15;;;634:58;;643:10;634:58;;;672:12;:19;;;634:58;;;;;;;;;;;;;;;709:4;702:11;;368:352;;;;:::o;5:118:-1:-;;72:46;110:6;97:20;72:46;;;63:55;;57:66;;;;;165:469;;282:4;270:9;265:3;261:19;257:30;254:2;;;300:1;297;290:12;254:2;318:20;333:4;318:20;;;309:29;;386:1;417:49;462:3;453:6;442:9;438:22;417:49;;;411:3;404:5;400:15;393:74;348:130;530:2;563:49;608:3;599:6;588:9;584:22;563:49;;;556:4;549:5;545:16;538:75;488:136;248:386;;;;;641:118;;708:46;746:6;733:20;708:46;;;699:55;;693:66;;;;;766:241;;870:2;858:9;849:7;845:23;841:32;838:2;;;886:1;883;876:12;838:2;921:1;938:53;983:7;974:6;963:9;959:22;938:53;;;928:63;;900:97;832:175;;;;;1014:297;;1146:2;1134:9;1125:7;1121:23;1117:32;1114:2;;;1162:1;1159;1152:12;1114:2;1197:1;1214:81;1287:7;1278:6;1267:9;1263:22;1214:81;;;1204:91;;1176:125;1108:203;;;;;1318:101;1385:28;1407:5;1385:28;;;1380:3;1373:41;1367:52;;;1426:110;1499:31;1524:5;1499:31;;;1494:3;1487:44;1481:55;;;1543:181;;1645:2;1634:9;1630:18;1622:26;;1659:55;1711:1;1700:9;1696:17;1687:6;1659:55;;;1616:108;;;;;1731:193;;1839:2;1828:9;1824:18;1816:26;;1853:61;1911:1;1900:9;1896:17;1887:6;1853:61;;;1810:114;;;;;1931:256;;1993:2;1987:9;1977:19;;2031:4;2023:6;2019:17;2130:6;2118:10;2115:22;2094:18;2082:10;2079:34;2076:62;2073:2;;;2151:1;2148;2141:12;2073:2;2171:10;2167:2;2160:22;1971:216;;;;;2194:92;;2274:5;2267:13;2260:21;2249:32;;2243:43;;;;2293:79;;2362:5;2351:16;;2345:27;;;;2379:128;;2459:42;2452:5;2448:54;2437:65;;2431:76;;;;2514:79;;2583:5;2572:16;;2566:27;;;", - "sources": ["Metacoin.sol"] + "bytecode": "0x6060604052341561000f57600080fd5b6127106000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550610613806100636000396000f300606060405260043610610062576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063135cfdb11461006757806327e235e31461009d5780632bd14bb9146100d35780632f8086ba14610109575b600080fd5b341561007257600080fd5b6100876004610082903690610446565b61013f565b604051610094919061051c565b60405180910390f35b34156100a857600080fd5b6100bd60046100b890369061041d565b61015a565b6040516100ca9190610537565b60405180910390f35b34156100de57600080fd5b6100f360046100ee90369061046f565b610172565b6040516101009190610501565b60405180910390f35b341561011457600080fd5b6101296004610124903690610498565b6102e2565b604051610136919061051c565b60405180910390f35b6000610153826000015183602001516102e2565b9050919050565b60006020528060005260406000206000915090505481565b600081602001516000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410156101c757600090506102dd565b81602001516000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825403925050819055508160200151600080846000015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540192505081905550816000015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84602001516040516102d09190610537565b60405180910390a3600190505b919050565b60006102ed83610172565b508163ffffffff16905092915050565b6000610309823561059f565b905092915050565b60006060828403121561032357600080fd5b61032d6040610552565b9050600061033d8482850161035d565b600083015250604061035184828501610409565b60208301525092915050565b60006040828403121561036f57600080fd5b6103796040610552565b90506000610389848285016102fd565b600083015250602061039d848285016103f5565b60208301525092915050565b6000604082840312156103bb57600080fd5b6103c56040610552565b905060006103d5848285016102fd565b60008301525060206103e9848285016103f5565b60208301525092915050565b600061040182356105bf565b905092915050565b600061041582356105c9565b905092915050565b60006020828403121561042f57600080fd5b600061043d848285016102fd565b91505092915050565b60006060828403121561045857600080fd5b600061046684828501610311565b91505092915050565b60006040828403121561048157600080fd5b600061048f848285016103a9565b91505092915050565b600080606083850312156104ab57600080fd5b60006104b9858286016103a9565b92505060406104ca85828601610409565b9150509250929050565b6104dd8161057f565b82525050565b6104ec8161058b565b82525050565b6104fb81610595565b82525050565b600060208201905061051660008301846104d4565b92915050565b600060208201905061053160008301846104e3565b92915050565b600060208201905061054c60008301846104f2565b92915050565b6000604051905081810181811067ffffffffffffffff8211171561057557600080fd5b8060405250919050565b60008115159050919050565b6000819050919050565b6000819050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b600063ffffffff821690509190505600a265627a7a72305820716a74dd7e2a73c237481496756750895b57977fc4876b1c48aef9b71759bf836c6578706572696d656e74616cf50037", + "runtime_bytecode": "0x606060405260043610610062576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063135cfdb11461006757806327e235e31461009d5780632bd14bb9146100d35780632f8086ba14610109575b600080fd5b341561007257600080fd5b6100876004610082903690610446565b61013f565b604051610094919061051c565b60405180910390f35b34156100a857600080fd5b6100bd60046100b890369061041d565b61015a565b6040516100ca9190610537565b60405180910390f35b34156100de57600080fd5b6100f360046100ee90369061046f565b610172565b6040516101009190610501565b60405180910390f35b341561011457600080fd5b6101296004610124903690610498565b6102e2565b604051610136919061051c565b60405180910390f35b6000610153826000015183602001516102e2565b9050919050565b60006020528060005260406000206000915090505481565b600081602001516000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410156101c757600090506102dd565b81602001516000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825403925050819055508160200151600080846000015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540192505081905550816000015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84602001516040516102d09190610537565b60405180910390a3600190505b919050565b60006102ed83610172565b508163ffffffff16905092915050565b6000610309823561059f565b905092915050565b60006060828403121561032357600080fd5b61032d6040610552565b9050600061033d8482850161035d565b600083015250604061035184828501610409565b60208301525092915050565b60006040828403121561036f57600080fd5b6103796040610552565b90506000610389848285016102fd565b600083015250602061039d848285016103f5565b60208301525092915050565b6000604082840312156103bb57600080fd5b6103c56040610552565b905060006103d5848285016102fd565b60008301525060206103e9848285016103f5565b60208301525092915050565b600061040182356105bf565b905092915050565b600061041582356105c9565b905092915050565b60006020828403121561042f57600080fd5b600061043d848285016102fd565b91505092915050565b60006060828403121561045857600080fd5b600061046684828501610311565b91505092915050565b60006040828403121561048157600080fd5b600061048f848285016103a9565b91505092915050565b600080606083850312156104ab57600080fd5b60006104b9858286016103a9565b92505060406104ca85828601610409565b9150509250929050565b6104dd8161057f565b82525050565b6104ec8161058b565b82525050565b6104fb81610595565b82525050565b600060208201905061051660008301846104d4565b92915050565b600060208201905061053160008301846104e3565b92915050565b600060208201905061054c60008301846104f2565b92915050565b6000604051905081810181811067ffffffffffffffff8211171561057557600080fd5b8060405250919050565b60008115159050919050565b6000819050919050565b6000819050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b600063ffffffff821690509190505600a265627a7a72305820716a74dd7e2a73c237481496756750895b57977fc4876b1c48aef9b71759bf836c6578706572696d656e74616cf50037", + "updated_at": 1522966321930, + "source_map": "60:1093:0:-;;;389:72;;;;;;;;449:5;426:8;:20;435:10;426:20;;;;;;;;;;;;;;;:28;;;;60:1093;;;;;;", + "source_map_runtime": "60:1093:0:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;978:172;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;84:41;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;467:352;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;825:147;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;978:172;1051:3;1073:70;1082:18;:31;;;1115:18;:27;;;1073:8;:70::i;:::-;1066:77;;978:172;;;:::o;84:41::-;;;;;;;;;;;;;;;;;:::o;467:352::-;528:12;579;:19;;;556:8;:20;565:10;556:20;;;;;;;;;;;;;;;;:42;552:60;;;607:5;600:12;;;;552:60;646:12;:19;;;622:8;:20;631:10;622:20;;;;;;;;;;;;;;;;:43;;;;;;;;;;;704:12;:19;;;675:8;:25;684:12;:15;;;675:25;;;;;;;;;;;;;;;;:48;;;;;;;;;;;754:12;:15;;;733:58;;742:10;733:58;;;771:12;:19;;;733:58;;;;;;;;;;;;;;;808:4;801:11;;467:352;;;;:::o;825:147::-;903:3;918:22;927:12;918:8;:22::i;:::-;;957:8;950:15;;;;825:147;;;;:::o;5:118:-1:-;;72:46;110:6;97:20;72:46;;;63:55;;57:66;;;;;171:510;;294:4;282:9;277:3;273:19;269:30;266:2;;;312:1;309;302:12;266:2;330:20;345:4;330:20;;;321:29;;408:1;439:73;508:3;499:6;488:9;484:22;439:73;;;433:3;426:5;422:15;415:98;360:164;578:2;611:48;655:3;646:6;635:9;631:22;611:48;;;604:4;597:5;593:16;586:74;534:137;260:421;;;;;723:465;;836:4;824:9;819:3;815:19;811:30;808:2;;;854:1;851;844:12;808:2;872:20;887:4;872:20;;;863:29;;940:1;971:49;1016:3;1007:6;996:9;992:22;971:49;;;965:3;958:5;954:15;947:74;902:130;1084:2;1117:49;1162:3;1153:6;1142:9;1138:22;1117:49;;;1110:4;1103:5;1099:16;1092:75;1042:136;802:386;;;;;1230:469;;1347:4;1335:9;1330:3;1326:19;1322:30;1319:2;;;1365:1;1362;1355:12;1319:2;1383:20;1398:4;1383:20;;;1374:29;;1451:1;1482:49;1527:3;1518:6;1507:9;1503:22;1482:49;;;1476:3;1469:5;1465:15;1458:74;1413:130;1595:2;1628:49;1673:3;1664:6;1653:9;1649:22;1628:49;;;1621:4;1614:5;1610:16;1603:75;1553:136;1313:386;;;;;1706:118;;1773:46;1811:6;1798:20;1773:46;;;1764:55;;1758:66;;;;;1831:116;;1897:45;1934:6;1921:20;1897:45;;;1888:54;;1882:65;;;;;1954:241;;2058:2;2046:9;2037:7;2033:23;2029:32;2026:2;;;2074:1;2071;2064:12;2026:2;2109:1;2126:53;2171:7;2162:6;2151:9;2147:22;2126:53;;;2116:63;;2088:97;2020:175;;;;;2202:309;;2340:2;2328:9;2319:7;2315:23;2311:32;2308:2;;;2356:1;2353;2346:12;2308:2;2391:1;2408:87;2487:7;2478:6;2467:9;2463:22;2408:87;;;2398:97;;2370:131;2302:209;;;;;2518:297;;2650:2;2638:9;2629:7;2625:23;2621:32;2618:2;;;2666:1;2663;2656:12;2618:2;2701:1;2718:81;2791:7;2782:6;2771:9;2767:22;2718:81;;;2708:91;;2680:125;2612:203;;;;;2822:420;;;2970:2;2958:9;2949:7;2945:23;2941:32;2938:2;;;2986:1;2983;2976:12;2938:2;3021:1;3038:81;3111:7;3102:6;3091:9;3087:22;3038:81;;;3028:91;;3000:125;3156:2;3174:52;3218:7;3209:6;3198:9;3194:22;3174:52;;;3164:62;;3135:97;2932:310;;;;;;3249:101;3316:28;3338:5;3316:28;;;3311:3;3304:41;3298:52;;;3357:107;3428:30;3452:5;3428:30;;;3423:3;3416:43;3410:54;;;3471:110;3544:31;3569:5;3544:31;;;3539:3;3532:44;3526:55;;;3588:181;;3690:2;3679:9;3675:18;3667:26;;3704:55;3756:1;3745:9;3741:17;3732:6;3704:55;;;3661:108;;;;;3776:189;;3882:2;3871:9;3867:18;3859:26;;3896:59;3952:1;3941:9;3937:17;3928:6;3896:59;;;3853:112;;;;;3972:193;;4080:2;4069:9;4065:18;4057:26;;4094:61;4152:1;4141:9;4137:17;4128:6;4094:61;;;4051:114;;;;;4172:256;;4234:2;4228:9;4218:19;;4272:4;4264:6;4260:17;4371:6;4359:10;4356:22;4335:18;4323:10;4320:34;4317:62;4314:2;;;4392:1;4389;4382:12;4314:2;4412:10;4408:2;4401:22;4212:216;;;;;4435:92;;4515:5;4508:13;4501:21;4490:32;;4484:43;;;;4534:78;;4602:5;4591:16;;4585:27;;;;4619:79;;4688:5;4677:16;;4671:27;;;;4705:128;;4785:42;4778:5;4774:54;4763:65;;4757:76;;;;4840:79;;4909:5;4898:16;;4892:27;;;;4926:95;;5005:10;4998:5;4994:22;4983:33;;4977:44;;;", + "sources": [ + "/Metacoin.sol" + ] } } -} +}
\ No newline at end of file diff --git a/packages/metacoin/contracts/Metacoin.sol b/packages/metacoin/contracts/Metacoin.sol index 6b6814b21..ac212b32e 100644 --- a/packages/metacoin/contracts/Metacoin.sol +++ b/packages/metacoin/contracts/Metacoin.sol @@ -11,6 +11,11 @@ contract Metacoin { uint256 amount; } + struct NestedTransferData { + TransferData transferData; + uint32 callback; + } + function Metacoin() public { balances[msg.sender] = 10000; } @@ -22,4 +27,14 @@ contract Metacoin { Transfer(msg.sender, transferData.to, transferData.amount); return true; } + + function transfer(TransferData transferData, uint32 callback) public returns (int) { + transfer(transferData); + return callback; + } + + function transfer(NestedTransferData nestedTransferData) public returns (int) { + return transfer(nestedTransferData.transferData, nestedTransferData.callback); + } + } diff --git a/packages/metacoin/package.json b/packages/metacoin/package.json index f63e1df61..8795be633 100644 --- a/packages/metacoin/package.json +++ b/packages/metacoin/package.json @@ -18,7 +18,7 @@ "coverage:report:html": "istanbul report html && open coverage/index.html", "coverage:report:lcov": "istanbul report lcov", "test:circleci": "yarn test:coverage", - "compile": "node ../deployer/lib/src/cli.js compile --contracts Metacoin --contracts-dir contracts --artifacts-dir artifacts" + "compile": "node ../deployer/lib/src/cli.js compile --contracts Metacoin --contract-dirs contracts --artifacts-dir artifacts" }, "author": "", "license": "Apache-2.0", diff --git a/packages/metacoin/test/metacoin_test.ts b/packages/metacoin/test/metacoin_test.ts index 73537d342..51830d1ef 100644 --- a/packages/metacoin/test/metacoin_test.ts +++ b/packages/metacoin/test/metacoin_test.ts @@ -36,12 +36,12 @@ describe('Metacoin', () => { }); }); describe('#transfer', () => { - it(`should successfully transfer tokens`, async () => { + it(`should successfully transfer tokens (via transfer1)`, async () => { const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'; const amount = INITIAL_BALANCE.div(2); const oldBalance = await metacoin.balances.callAsync(ZERO_ADDRESS); expect(oldBalance).to.be.bignumber.equal(0); - const txHash = await metacoin.transfer.sendTransactionAsync( + const txHash = await metacoin.transfer1.sendTransactionAsync( { to: ZERO_ADDRESS, amount, @@ -58,5 +58,57 @@ describe('Metacoin', () => { const newBalance = await metacoin.balances.callAsync(ZERO_ADDRESS); expect(newBalance).to.be.bignumber.equal(amount); }); + + it(`should successfully transfer tokens (via transfer2)`, async () => { + const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'; + const amount = INITIAL_BALANCE.div(2); + const oldBalance = await metacoin.balances.callAsync(ZERO_ADDRESS); + expect(oldBalance).to.be.bignumber.equal(0); + const callback = 59; + const txHash = await metacoin.transfer2.sendTransactionAsync( + { + to: ZERO_ADDRESS, + amount, + }, + callback, + { from: devConstants.TESTRPC_FIRST_ADDRESS }, + ); + const txReceipt = await web3Wrapper.awaitTransactionMinedAsync(txHash); + const transferLogs = txReceipt.logs[0] as LogWithDecodedArgs<TransferContractEventArgs>; + expect(transferLogs.args).to.be.deep.equal({ + _to: ZERO_ADDRESS, + _from: devConstants.TESTRPC_FIRST_ADDRESS, + _value: amount, + }); + const newBalance = await metacoin.balances.callAsync(ZERO_ADDRESS); + expect(newBalance).to.be.bignumber.equal(amount); + }); + + it(`should successfully transfer tokens (via transfer3)`, async () => { + const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'; + const amount = INITIAL_BALANCE.div(2); + const oldBalance = await metacoin.balances.callAsync(ZERO_ADDRESS); + expect(oldBalance).to.be.bignumber.equal(0); + const callback = 59; + const txHash = await metacoin.transfer3.sendTransactionAsync( + { + transferData: { + to: ZERO_ADDRESS, + amount, + }, + callback, + }, + { from: devConstants.TESTRPC_FIRST_ADDRESS }, + ); + const txReceipt = await web3Wrapper.awaitTransactionMinedAsync(txHash); + const transferLogs = txReceipt.logs[0] as LogWithDecodedArgs<TransferContractEventArgs>; + expect(transferLogs.args).to.be.deep.equal({ + _to: ZERO_ADDRESS, + _from: devConstants.TESTRPC_FIRST_ADDRESS, + _value: amount, + }); + const newBalance = await metacoin.balances.callAsync(ZERO_ADDRESS); + expect(newBalance).to.be.bignumber.equal(amount); + }); }); }); diff --git a/packages/monorepo-scripts/package.json b/packages/monorepo-scripts/package.json index b113b4b39..5c0e5a411 100644 --- a/packages/monorepo-scripts/package.json +++ b/packages/monorepo-scripts/package.json @@ -29,6 +29,7 @@ "@0xproject/tslint-config": "0.4.13", "@types/glob": "^5.0.33", "@types/node": "^8.0.53", + "@types/opn": "^5.1.0", "@types/rimraf": "^2.0.2", "depcheck": "^0.6.9", "lerna-get-packages": "^1.0.0", @@ -45,7 +46,9 @@ "glob": "^7.1.2", "lodash": "^4.17.4", "moment": "2.21.0", + "opn": "^5.3.0", "promisify-child-process": "^1.0.5", + "prompt": "^1.0.0", "publish-release": "0xproject/publish-release", "rimraf": "^2.6.2", "semver-diff": "^2.1.0", diff --git a/packages/monorepo-scripts/src/constants.ts b/packages/monorepo-scripts/src/constants.ts index 74387a159..081a49332 100644 --- a/packages/monorepo-scripts/src/constants.ts +++ b/packages/monorepo-scripts/src/constants.ts @@ -2,4 +2,5 @@ import * as path from 'path'; export const constants = { monorepoRootPath: path.join(__dirname, '../../..'), + stagingWebsite: 'http://staging-0xproject.s3-website-us-east-1.amazonaws.com', }; diff --git a/packages/monorepo-scripts/src/globals.d.ts b/packages/monorepo-scripts/src/globals.d.ts index c5898d0f5..1693a6dbb 100644 --- a/packages/monorepo-scripts/src/globals.d.ts +++ b/packages/monorepo-scripts/src/globals.d.ts @@ -3,6 +3,11 @@ declare module 'publish-release'; declare module 'es6-promisify'; declare module 'semver-diff'; +declare module 'prompt' { + const start: () => void; + const get: (promptMessages: string[], callback: (err: Error, result: string) => void) => void; +} + // semver-sort declarations declare module 'semver-sort' { const desc: (versions: string[]) => string[]; @@ -15,6 +20,7 @@ declare interface LernaPackage { version: string; name: string; main?: string; + scripts?: { [command: string]: string }; config?: { additionalTsTypings?: string[]; }; diff --git a/packages/monorepo-scripts/src/publish.ts b/packages/monorepo-scripts/src/publish.ts index adc1de64a..21c8b72c9 100644 --- a/packages/monorepo-scripts/src/publish.ts +++ b/packages/monorepo-scripts/src/publish.ts @@ -1,18 +1,23 @@ #!/usr/bin/env node +import * as promisify from 'es6-promisify'; import * as fs from 'fs'; import lernaGetPackages = require('lerna-get-packages'); import * as _ from 'lodash'; import * as moment from 'moment'; +import opn = require('opn'); import * as path from 'path'; import { exec as execAsync, spawn } from 'promisify-child-process'; +import * as prompt from 'prompt'; import semverDiff = require('semver-diff'); import semverSort = require('semver-sort'); import { constants } from './constants'; -import { Changelog, Changes, SemVerIndex, UpdatedPackage } from './types'; +import { Changelog, Changes, PackageToVersionChange, SemVerIndex, UpdatedPackage } from './types'; import { utils } from './utils'; +const DOC_GEN_COMMAND = 'docs:json'; +const NPM_NAMESPACE = '@0xproject/'; const IS_DRY_RUN = process.env.IS_DRY_RUN === 'true'; const TODAYS_TIMESTAMP = moment().unix(); const LERNA_EXECUTABLE = './node_modules/lerna/bin/lerna.js'; @@ -21,8 +26,95 @@ const semverNameToIndex: { [semver: string]: number } = { minor: SemVerIndex.Minor, major: SemVerIndex.Major, }; +const packageNameToWebsitePath: { [name: string]: string } = { + '0x.js': '0xjs', + 'web3-wrapper': 'web3_wrapper', + contracts: 'contracts', + connect: 'connect', + 'json-schemas': 'json-schemas', + deployer: 'deployer', + 'sol-cov': 'sol-cov', + subproviders: 'subproviders', +}; (async () => { + // Fetch public, updated Lerna packages + const updatedPublicLernaPackages = await getUpdatedPublicLernaPackagesAsync(); + + await confirmDocPagesRenderAsync(updatedPublicLernaPackages); + + // Update CHANGELOGs + const updatedPublicLernaPackageNames = _.map(updatedPublicLernaPackages, pkg => pkg.package.name); + utils.log(`Will update CHANGELOGs and publish: \n${updatedPublicLernaPackageNames.join('\n')}\n`); + const packageToVersionChange = await updateChangeLogsAsync(updatedPublicLernaPackages); + + // Push changelog changes to Github + if (!IS_DRY_RUN) { + await pushChangelogsToGithubAsync(); + } + + // Call LernaPublish + utils.log('Version updates to apply:'); + _.each(packageToVersionChange, (versionChange: string, packageName: string) => { + utils.log(`${packageName} -> ${versionChange}`); + }); + utils.log(`Calling 'lerna publish'...`); + await lernaPublishAsync(packageToVersionChange); +})().catch(err => { + utils.log(err); + process.exit(1); +}); + +async function confirmDocPagesRenderAsync(packages: LernaPackage[]) { + // push docs to staging + utils.log("Upload all docJson's to S3 staging..."); + await execAsync(`yarn lerna:stage_docs`, { cwd: constants.monorepoRootPath }); + + // deploy website to staging + utils.log('Deploy website to staging...'); + const pathToWebsite = `${constants.monorepoRootPath}/packages/website`; + await execAsync(`yarn deploy_staging`, { cwd: pathToWebsite }); + + const packagesWithDocs = _.filter(packages, pkg => { + const scriptsIfExists = pkg.package.scripts; + if (_.isUndefined(scriptsIfExists)) { + throw new Error('Found a public package without any scripts in package.json'); + } + return !_.isUndefined(scriptsIfExists[DOC_GEN_COMMAND]); + }); + _.each(packagesWithDocs, pkg => { + const name = pkg.package.name; + const nameWithoutPrefix = _.startsWith(name, NPM_NAMESPACE) ? name.split('@0xproject/')[1] : name; + const docSegmentIfExists = packageNameToWebsitePath[nameWithoutPrefix]; + if (_.isUndefined(docSegmentIfExists)) { + throw new Error( + `Found package '${name}' with doc commands but no corresponding docSegment in monorepo_scripts +package.ts. Please add an entry for it and try again.`, + ); + } + const link = `${constants.stagingWebsite}/docs/${docSegmentIfExists}`; + // tslint:disable-next-line:no-floating-promises + opn(link); + }); + + prompt.start(); + const message = 'Do all the doc pages render properly? (yn)'; + const result = await promisify(prompt.get)([message]); + const didConfirm = result[message] === 'y'; + if (!didConfirm) { + utils.log('Publish process aborted.'); + process.exit(0); + } +} + +async function pushChangelogsToGithubAsync() { + await execAsync(`git add . --all`, { cwd: constants.monorepoRootPath }); + await execAsync(`git commit -m "Updated CHANGELOGS"`, { cwd: constants.monorepoRootPath }); + await execAsync(`git push`, { cwd: constants.monorepoRootPath }); + utils.log(`Pushed CHANGELOG updates to Github`); +} + +async function getUpdatedPublicLernaPackagesAsync(): Promise<LernaPackage[]> { const updatedPublicPackages = await getPublicLernaUpdatedPackagesAsync(); const updatedPackageNames = _.map(updatedPublicPackages, pkg => pkg.name); @@ -30,10 +122,11 @@ const semverNameToIndex: { [semver: string]: number } = { const updatedPublicLernaPackages = _.filter(allLernaPackages, pkg => { return _.includes(updatedPackageNames, pkg.package.name); }); - const updatedPublicLernaPackageNames = _.map(updatedPublicLernaPackages, pkg => pkg.package.name); - utils.log(`Will update CHANGELOGs and publish: \n${updatedPublicLernaPackageNames.join('\n')}\n`); + return updatedPublicLernaPackages; +} - const packageToVersionChange: { [name: string]: string } = {}; +async function updateChangeLogsAsync(updatedPublicLernaPackages: LernaPackage[]): Promise<PackageToVersionChange> { + const packageToVersionChange: PackageToVersionChange = {}; for (const lernaPackage of updatedPublicLernaPackages) { const packageName = lernaPackage.package.name; const changelogJSONPath = path.join(lernaPackage.location, 'CHANGELOG.json'); @@ -88,23 +181,8 @@ const semverNameToIndex: { [semver: string]: number } = { utils.log(`${packageName}: Updated CHANGELOG.md`); } - if (!IS_DRY_RUN) { - await execAsync(`git add . --all`, { cwd: constants.monorepoRootPath }); - await execAsync(`git commit -m "Updated CHANGELOGS"`, { cwd: constants.monorepoRootPath }); - await execAsync(`git push`, { cwd: constants.monorepoRootPath }); - utils.log(`Pushed CHANGELOG updates to Github`); - } - - utils.log('Version updates to apply:'); - _.each(packageToVersionChange, (versionChange: string, packageName: string) => { - utils.log(`${packageName} -> ${versionChange}`); - }); - utils.log(`Calling 'lerna publish'...`); - await lernaPublishAsync(packageToVersionChange); -})().catch(err => { - utils.log(err); - process.exit(1); -}); + return packageToVersionChange; +} async function lernaPublishAsync(packageToVersionChange: { [name: string]: string }) { // HACK: Lerna publish does not provide a way to specify multiple package versions via diff --git a/packages/monorepo-scripts/src/types.ts b/packages/monorepo-scripts/src/types.ts index 9e6edd186..28d00d710 100644 --- a/packages/monorepo-scripts/src/types.ts +++ b/packages/monorepo-scripts/src/types.ts @@ -21,3 +21,7 @@ export enum SemVerIndex { Minor, Major, } + +export interface PackageToVersionChange { + [name: string]: string; +} diff --git a/packages/sol-cov/README.md b/packages/sol-cov/README.md index 8cc7dca6c..3a0377521 100644 --- a/packages/sol-cov/README.md +++ b/packages/sol-cov/README.md @@ -2,7 +2,7 @@ A Solidity code coverage tool. -### Read the [Documentation](0xproject.com/docs/sol-cov). +### Read the [Documentation](https://0xproject.com/docs/sol-cov). ## Installation diff --git a/packages/subproviders/README.md b/packages/subproviders/README.md index 2936be545..8c8807895 100644 --- a/packages/subproviders/README.md +++ b/packages/subproviders/README.md @@ -4,7 +4,7 @@ A few useful web3 subproviders including a LedgerSubprovider useful for adding L We have written up a [Wiki](https://0xproject.com/wiki#Web3-Provider-Examples) article detailing some use cases of this subprovider package. -### Read the [Documentation](0xproject.com/docs/subproviders). +### Read the [Documentation](https://0xproject.com/docs/subproviders). ## Installation diff --git a/packages/utils/src/abi_utils.ts b/packages/utils/src/abi_utils.ts new file mode 100644 index 000000000..c4533d42e --- /dev/null +++ b/packages/utils/src/abi_utils.ts @@ -0,0 +1,71 @@ +import { AbiDefinition, AbiType, ConstructorAbi, ContractAbi, DataItem, MethodAbi } from '@0xproject/types'; +import * as _ from 'lodash'; + +export const abiUtils = { + parseFunctionParam(param: DataItem): string { + if (param.type === 'tuple') { + // Parse out tuple types into {type_1, type_2, ..., type_N} + const tupleComponents = param.components; + const paramString = _.map(tupleComponents, component => this.parseFunctionParam(component)); + const tupleParamString = `{${paramString}}`; + return tupleParamString; + } + return param.type; + }, + getFunctionSignature(methodAbi: MethodAbi): string { + const functionName = methodAbi.name; + const parameterTypeList = _.map(methodAbi.inputs, (param: DataItem) => this.parseFunctionParam(param)); + const functionSignature = `${functionName}(${parameterTypeList})`; + return functionSignature; + }, + /** + * Solidity supports function overloading whereas TypeScript does not. + * See: https://solidity.readthedocs.io/en/v0.4.21/contracts.html?highlight=overload#function-overloading + * In order to support overloaded functions, we suffix overloaded function names with an index. + * This index should be deterministic, regardless of function ordering within the smart contract. To do so, + * we assign indexes based on the alphabetical order of function signatures. + * + * E.g + * ['f(uint)', 'f(uint,byte32)'] + * Should always be renamed to: + * ['f1(uint)', 'f2(uint,byte32)'] + * Regardless of the order in which these these overloaded functions are declared within the contract ABI. + */ + renameOverloadedMethods(inputContractAbi: ContractAbi): ContractAbi { + const contractAbi = _.cloneDeep(inputContractAbi); + const methodAbis = contractAbi.filter((abi: AbiDefinition) => abi.type === AbiType.Function) as MethodAbi[]; + // Sort method Abis into alphabetical order, by function signature + const methodAbisOrdered = _.sortBy(methodAbis, [ + (methodAbi: MethodAbi) => { + const functionSignature = this.getFunctionSignature(methodAbi); + return functionSignature; + }, + ]); + // Group method Abis by name (overloaded methods will be grouped together, in alphabetical order) + const methodAbisByName: { [key: string]: MethodAbi[] } = {}; + _.each(methodAbisOrdered, methodAbi => { + (methodAbisByName[methodAbi.name] || (methodAbisByName[methodAbi.name] = [])).push(methodAbi); + }); + // Rename overloaded methods to overloadedMethodName1, overloadedMethodName2, ... + _.each(methodAbisByName, methodAbisWithSameName => { + _.each(methodAbisWithSameName, (methodAbi, i: number) => { + if (methodAbisWithSameName.length > 1) { + const overloadedMethodId = i + 1; + const sanitizedMethodName = `${methodAbi.name}${overloadedMethodId}`; + const indexOfExistingAbiWithSanitizedMethodNameIfExists = _.findIndex( + methodAbis, + currentMethodAbi => currentMethodAbi.name === sanitizedMethodName, + ); + if (indexOfExistingAbiWithSanitizedMethodNameIfExists >= 0) { + const methodName = methodAbi.name; + throw new Error( + `Failed to rename overloaded method '${methodName}' to '${sanitizedMethodName}'. A method with this name already exists.`, + ); + } + methodAbi.name = sanitizedMethodName; + } + }); + }); + return contractAbi; + }, +}; diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts index debcce746..0da4b265d 100644 --- a/packages/utils/src/index.ts +++ b/packages/utils/src/index.ts @@ -5,3 +5,4 @@ export { intervalUtils } from './interval_utils'; export { BigNumber } from './configured_bignumber'; export { AbiDecoder } from './abi_decoder'; export { logUtils } from './log_utils'; +export { abiUtils } from './abi_utils'; diff --git a/packages/web3-wrapper/README.md b/packages/web3-wrapper/README.md index 1ff85420a..a38f49e6e 100644 --- a/packages/web3-wrapper/README.md +++ b/packages/web3-wrapper/README.md @@ -2,7 +2,7 @@ Wrapped version of web3 with a nicer interface that is used across 0x projects and packages. -### Read the [Documentation](0xproject.com/docs/web3_wrapper). +### Read the [Documentation](https://0xproject.com/docs/web3_wrapper). ## Installation diff --git a/packages/web3-wrapper/package.json b/packages/web3-wrapper/package.json index 910d4725e..5b5f42434 100644 --- a/packages/web3-wrapper/package.json +++ b/packages/web3-wrapper/package.json @@ -6,7 +6,7 @@ "types": "lib/src/index.d.ts", "scripts": { "build:watch": "tsc -w", - "build": "tsc && copyfiles -u 2 './lib/monorepo_scripts/**/*' ./scripts", + "build": "tsc && copyfiles -u 3 './lib/src/monorepo_scripts/**/*' ./scripts", "clean": "shx rm -rf lib scripts", "lint": "tslint --project . 'src/**/*.ts'", "test": "run-s clean build run_mocha", @@ -6,6 +6,41 @@ version "0.3.9" resolved "https://registry.yarnpkg.com/8fold-marked/-/8fold-marked-0.3.9.tgz#bb89c645612f8ccfaffac1ca6e3c11f168c9cf59" +"@0xproject/dev-utils@^0.2.1": + version "0.2.1" + resolved "https://registry.yarnpkg.com/@0xproject/dev-utils/-/dev-utils-0.2.1.tgz#a54465376fd7c8cf58781b02b1790d74fb51e91b" + dependencies: + "@0xproject/subproviders" "^0.7.0" + "@0xproject/types" "^0.3.1" + "@0xproject/utils" "^0.4.1" + ethereumjs-util "^5.1.2" + lodash "^4.17.4" + request-promise-native "^1.0.5" + web3 "^0.20.0" + web3-provider-engine "^13.0.1" + +"@0xproject/subproviders@^0.7.0": + version "0.7.0" + resolved "https://registry.yarnpkg.com/@0xproject/subproviders/-/subproviders-0.7.0.tgz#ce3379a85649773e5c08f5fc3239e8ed07f13361" + dependencies: + "@0xproject/assert" "^0.2.0" + "@0xproject/types" "^0.3.1" + "@0xproject/utils" "^0.4.1" + "@ledgerhq/hw-app-eth" "^4.3.0" + "@ledgerhq/hw-transport-u2f" "^4.3.0" + bn.js "^4.11.8" + es6-promisify "^5.0.0" + ethereumjs-tx "^1.3.3" + ethereumjs-util "^5.1.1" + hdkey "^0.7.1" + lodash "^4.17.4" + semaphore-async-await "^1.5.1" + web3 "^0.20.0" + web3-provider-engine "^13.0.1" + web3-typescript-typings "^0.10.0" + optionalDependencies: + "@ledgerhq/hw-transport-node-hid" "^4.3.0" + "@0xproject/tslint-config@0.4.13": version "0.4.13" resolved "https://registry.yarnpkg.com/@0xproject/tslint-config/-/tslint-config-0.4.13.tgz#98c71c5ae5e80315a23eda0134cc9f6f4438cac2" @@ -15,6 +50,40 @@ tslint-eslint-rules "^4.1.1" tslint-react "^3.2.0" +"@0xproject/types@^0.3.1": + version "0.3.1" + resolved "https://registry.yarnpkg.com/@0xproject/types/-/types-0.3.1.tgz#9a75be6d3a2d41b7ecbd9105c3fdc09f3e3ec297" + dependencies: + bignumber.js "~4.1.0" + web3 "^0.20.0" + web3-typescript-typings "^0.10.0" + +"@0xproject/types@^0.4.2": + version "0.4.2" + resolved "https://registry.yarnpkg.com/@0xproject/types/-/types-0.4.2.tgz#83d6ebef60f41e6209acb2656b1d68ff79367ca5" + dependencies: + bignumber.js "~4.1.0" + +"@0xproject/typescript-typings@^0.0.2": + version "0.0.2" + resolved "https://registry.yarnpkg.com/@0xproject/typescript-typings/-/typescript-typings-0.0.2.tgz#b549ea3c81ce2d81b99f05583bdf7c411a3ca90c" + dependencies: + "@0xproject/types" "^0.4.2" + bignumber.js "~4.1.0" + +"@0xproject/utils@^0.4.1": + version "0.4.4" + resolved "https://registry.yarnpkg.com/@0xproject/utils/-/utils-0.4.4.tgz#bce4f7a5a46570a69911f4a4ade5d49016330087" + dependencies: + "@0xproject/types" "^0.4.2" + "@0xproject/typescript-typings" "^0.0.2" + "@types/node" "^8.0.53" + bignumber.js "~4.1.0" + ethers-contracts "^2.2.1" + js-sha3 "^0.7.0" + lodash "^4.17.4" + web3 "^0.20.0" + "@ledgerhq/hw-app-eth@^4.3.0": version "4.7.3" resolved "https://registry.yarnpkg.com/@ledgerhq/hw-app-eth/-/hw-app-eth-4.7.3.tgz#d352e19658ae296532e522c53c8ec2a1a77b64e5" @@ -220,6 +289,12 @@ version "8.10.0" resolved "https://registry.yarnpkg.com/@types/node/-/node-8.10.0.tgz#f5d649cc49af8ed6507d15dc6e9b43fe8b927540" +"@types/opn@^5.1.0": + version "5.1.0" + resolved "https://registry.yarnpkg.com/@types/opn/-/opn-5.1.0.tgz#bff7bc371677f4bdbb37884400e03fd81f743927" + dependencies: + "@types/node" "*" + "@types/query-string@^5.0.1": version "5.1.0" resolved "https://registry.yarnpkg.com/@types/query-string/-/query-string-5.1.0.tgz#7f40cdea49ddafa0ea4f3db35fb6c24d3bfd4dcc" @@ -734,10 +809,14 @@ async@2.6.0, async@^2.0.1, async@^2.1.2, async@^2.4.0, async@^2.5.0: dependencies: lodash "^4.14.0" -async@^0.9.0: +async@^0.9.0, async@~0.9.0: version "0.9.2" resolved "https://registry.yarnpkg.com/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d" +async@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/async/-/async-1.0.0.tgz#f8fc04ca3a13784ade9e1641af98578cfbd647a9" + async@~1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/async/-/async-1.2.1.tgz#a4816a17cd5ff516dfa2c7698a453369b9790de0" @@ -2151,6 +2230,10 @@ colormin@^1.0.5: css-color-names "0.0.4" has "^1.0.1" +colors@1.0.x: + version "1.0.3" + resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b" + colors@1.1.2, colors@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63" @@ -2741,6 +2824,10 @@ currently-unhandled@^0.4.1: dependencies: array-find-index "^1.0.1" +cycle@1.0.x: + version "1.0.3" + resolved "https://registry.yarnpkg.com/cycle/-/cycle-1.0.3.tgz#21e80b2be8580f98b468f379430662b046c34ad2" + cyclist@~0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-0.2.2.tgz#1b33792e11e914a2fd6d6ed6447464444e5fa640" @@ -2906,6 +2993,10 @@ deep-equal@^1.0.0, deep-equal@^1.0.1, deep-equal@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5" +deep-equal@~0.2.1: + version "0.2.2" + resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-0.2.2.tgz#84b745896f34c684e98f2ce0e42abaf43bba017d" + deep-extend@~0.4.0: version "0.4.2" resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.2.tgz#48b699c27e334bf89f10892be432f6e4c7d34a7f" @@ -3562,7 +3653,7 @@ ethereumjs-util@^4.0.1, ethereumjs-util@^4.3.0, ethereumjs-util@^4.4.0: rlp "^2.0.0" secp256k1 "^3.0.1" -ethereumjs-util@^5.0.0, ethereumjs-util@^5.0.1, ethereumjs-util@^5.1.1, ethereumjs-util@^5.1.3, ethereumjs-util@^5.1.5: +ethereumjs-util@^5.0.0, ethereumjs-util@^5.0.1, ethereumjs-util@^5.1.1, ethereumjs-util@^5.1.2, ethereumjs-util@^5.1.3, ethereumjs-util@^5.1.5: version "5.1.5" resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-5.1.5.tgz#2f02575852627d45622426f25ee4a0b5f377f27a" dependencies: @@ -3847,6 +3938,10 @@ extsprintf@^1.2.0: version "1.4.0" resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" +eyes@0.1.x: + version "0.1.8" + resolved "https://registry.yarnpkg.com/eyes/-/eyes-0.1.8.tgz#62cf120234c683785d902348a800ef3e0cc20bc0" + fake-merkle-patricia-tree@^1.0.1, fake-merkle-patricia-tree@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/fake-merkle-patricia-tree/-/fake-merkle-patricia-tree-1.0.1.tgz#4b8c3acfb520afadf9860b1f14cd8ce3402cddd3" @@ -5034,6 +5129,10 @@ hyphenate-style-name@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/hyphenate-style-name/-/hyphenate-style-name-1.0.2.tgz#31160a36930adaf1fc04c6074f7eb41465d4ec4b" +i@0.3.x: + version "0.3.6" + resolved "https://registry.yarnpkg.com/i/-/i-0.3.6.tgz#d96c92732076f072711b6b10fd7d4f65ad8ee23d" + iconv-lite@0.4.19, iconv-lite@^0.4.17, iconv-lite@~0.4.13: version "0.4.19" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" @@ -5597,7 +5696,7 @@ isomorphic-fetch@^2.1.1, isomorphic-fetch@^2.2.0, isomorphic-fetch@^2.2.1: node-fetch "^1.0.1" whatwg-fetch ">=0.10.0" -isstream@~0.1.2: +isstream@0.1.x, isstream@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" @@ -6771,7 +6870,7 @@ mkdirp-promise@^5.0.1: dependencies: mkdirp "*" -mkdirp@*, mkdirp@0.5.1, mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1: +mkdirp@*, mkdirp@0.5.1, mkdirp@0.5.x, mkdirp@0.x.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" dependencies: @@ -6909,6 +7008,10 @@ natives@^1.1.0: version "1.1.2" resolved "https://registry.yarnpkg.com/natives/-/natives-1.1.2.tgz#4437ca1ed8a7f047531ccdfaf2792853df4efa1c" +ncp@1.0.x: + version "1.0.1" + resolved "https://registry.yarnpkg.com/ncp/-/ncp-1.0.1.tgz#d15367e5cb87432ba117d2bf80fdf45aecfb4246" + negotiator@0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" @@ -7326,7 +7429,7 @@ opn@^4.0.0: object-assign "^4.0.1" pinkie-promise "^2.0.0" -opn@^5.1.0: +opn@^5.1.0, opn@^5.3.0: version "5.3.0" resolved "https://registry.yarnpkg.com/opn/-/opn-5.3.0.tgz#64871565c863875f052cfdf53d3e3cb5adb53b1c" dependencies: @@ -7683,10 +7786,14 @@ pkg-dir@^2.0.0: dependencies: find-up "^2.1.0" -pkginfo@^0.3.0: +pkginfo@0.3.x, pkginfo@^0.3.0: version "0.3.1" resolved "https://registry.yarnpkg.com/pkginfo/-/pkginfo-0.3.1.tgz#5b29f6a81f70717142e09e765bbeab97b4f81e21" +pkginfo@0.x.x: + version "0.4.1" + resolved "https://registry.yarnpkg.com/pkginfo/-/pkginfo-0.4.1.tgz#b5418ef0439de5425fc4995042dced14fb2a84ff" + plur@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/plur/-/plur-2.1.2.tgz#7482452c1a0f508e3e344eaec312c91c29dc655a" @@ -8176,6 +8283,17 @@ promisify-child-process@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/promisify-child-process/-/promisify-child-process-1.0.5.tgz#817ad1aec92c013d83bb37e1f143e9b4033d9669" +prompt@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/prompt/-/prompt-1.0.0.tgz#8e57123c396ab988897fb327fd3aedc3e735e4fe" + dependencies: + colors "^1.1.2" + pkginfo "0.x.x" + read "1.0.x" + revalidator "0.1.x" + utile "0.3.x" + winston "2.1.x" + prop-types@^15.5.10, prop-types@^15.5.4, prop-types@^15.5.6, prop-types@^15.5.7, prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.1: version "15.6.1" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.1.tgz#36644453564255ddda391191fb3a125cbdf654ca" @@ -8648,7 +8766,7 @@ read-pkg@^3.0.0: normalize-package-data "^2.3.2" path-type "^3.0.0" -read@~1.0.5: +read@1.0.x, read@~1.0.5: version "1.0.7" resolved "https://registry.yarnpkg.com/read/-/read-1.0.7.tgz#b3da19bd052431a97671d44a42634adf710b40c4" dependencies: @@ -8870,6 +8988,20 @@ request-ip@~1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/request-ip/-/request-ip-1.2.3.tgz#66988f0e22406ec4af630d19b573fe4b447c3b49" +request-promise-core@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/request-promise-core/-/request-promise-core-1.1.1.tgz#3eee00b2c5aa83239cfb04c5700da36f81cd08b6" + dependencies: + lodash "^4.13.1" + +request-promise-native@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/request-promise-native/-/request-promise-native-1.0.5.tgz#5281770f68e0c9719e5163fd3fab482215f4fda5" + dependencies: + request-promise-core "1.1.1" + stealthy-require "^1.1.0" + tough-cookie ">=2.3.3" + request@2.81.0: version "2.81.0" resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0" @@ -9014,13 +9146,17 @@ ret@~0.1.10: version "0.1.15" resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" +revalidator@0.1.x: + version "0.1.8" + resolved "https://registry.yarnpkg.com/revalidator/-/revalidator-0.1.8.tgz#fece61bfa0c1b52a206bd6b18198184bdd523a3b" + right-align@^0.1.1: version "0.1.3" resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef" dependencies: align-text "^0.1.1" -rimraf@2, rimraf@^2.2.8, rimraf@^2.5.1, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2: +rimraf@2, rimraf@2.x.x, rimraf@^2.2.8, rimraf@^2.5.1, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2: version "2.6.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" dependencies: @@ -9732,7 +9868,7 @@ stack-trace@0.0.9: version "0.0.9" resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.9.tgz#a8f6eaeca90674c333e7c43953f275b451510695" -stack-trace@~0.0.9: +stack-trace@0.0.x, stack-trace@~0.0.9: version "0.0.10" resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0" @@ -9751,6 +9887,10 @@ static-extend@^0.1.1: version "1.4.0" resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087" +stealthy-require@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b" + stream-browserify@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.1.tgz#66266ee5f9bdb9940a4e4514cafb43bb71e5c9db" @@ -10323,7 +10463,7 @@ touch@^3.1.0: dependencies: nopt "~1.0.10" -tough-cookie@~2.3.0, tough-cookie@~2.3.3: +tough-cookie@>=2.3.3, tough-cookie@~2.3.0, tough-cookie@~2.3.3: version "2.3.4" resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.4.tgz#ec60cee38ac675063ffc97a5c18970578ee83655" dependencies: @@ -10855,6 +10995,17 @@ util@0.10.3, util@^0.10.3: dependencies: inherits "2.0.1" +utile@0.3.x: + version "0.3.0" + resolved "https://registry.yarnpkg.com/utile/-/utile-0.3.0.tgz#1352c340eb820e4d8ddba039a4fbfaa32ed4ef3a" + dependencies: + async "~0.9.0" + deep-equal "~0.2.1" + i "0.3.x" + mkdirp "0.x.x" + ncp "1.0.x" + rimraf "2.x.x" + utils-merge@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" @@ -11267,7 +11418,7 @@ web3-shh@1.0.0-beta.33: web3-core-subscriptions "1.0.0-beta.33" web3-net "1.0.0-beta.33" -web3-typescript-typings@^0.10.2: +web3-typescript-typings@^0.10.0, web3-typescript-typings@^0.10.2: version "0.10.2" resolved "https://registry.yarnpkg.com/web3-typescript-typings/-/web3-typescript-typings-0.10.2.tgz#a9903815d2a8a0dbd73fd5db374070de0bd30497" dependencies: @@ -11481,6 +11632,18 @@ window-size@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.2.0.tgz#b4315bb4214a3d7058ebeee892e13fa24d98b075" +winston@2.1.x: + version "2.1.1" + resolved "https://registry.yarnpkg.com/winston/-/winston-2.1.1.tgz#3c9349d196207fd1bdff9d4bc43ef72510e3a12e" + dependencies: + async "~1.0.0" + colors "1.0.x" + cycle "1.0.x" + eyes "0.1.x" + isstream "0.1.x" + pkginfo "0.3.x" + stack-trace "0.0.x" + word-wrap@1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" |