From f2f9bd2e7ac1372073644a4e30a5d99e8c57fbb1 Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Tue, 10 Apr 2018 13:44:15 +0200 Subject: Revert "Merge pull request #493 from hysz/features/deployer/multipleCodebaseSupport" This reverts commit 70d403e6f8c56bc70e6d3471a770b9bbff5d72e7, reversing changes made to 073bf738ddb271b6b4158798baf4cac3cb0608e9. --- packages/deployer/package.json | 1 - packages/deployer/src/cli.ts | 37 +- packages/deployer/src/compiler.ts | 107 ++-- packages/deployer/src/utils/compiler.ts | 65 +-- packages/deployer/src/utils/contract.ts | 4 +- packages/deployer/src/utils/encoder.ts | 4 +- packages/deployer/src/utils/types.ts | 19 +- packages/deployer/test/compiler_test.ts | 16 +- packages/deployer/test/compiler_utils_test.ts | 22 +- packages/deployer/test/deployer_test.ts | 16 +- .../deployer/test/fixtures/contracts/Exchange.sol | 602 +++++++++++++++++++++ .../test/fixtures/contracts/TokenTransferProxy.sol | 115 ++++ .../test/fixtures/contracts/main/Exchange.sol | 602 --------------------- .../fixtures/contracts/main/TokenTransferProxy.sol | 115 ---- 14 files changed, 790 insertions(+), 935 deletions(-) create mode 100644 packages/deployer/test/fixtures/contracts/Exchange.sol create mode 100644 packages/deployer/test/fixtures/contracts/TokenTransferProxy.sol delete mode 100644 packages/deployer/test/fixtures/contracts/main/Exchange.sol delete mode 100644 packages/deployer/test/fixtures/contracts/main/TokenTransferProxy.sol (limited to 'packages/deployer') diff --git a/packages/deployer/package.json b/packages/deployer/package.json index 6afaa13b3..ef5c1cd16 100644 --- a/packages/deployer/package.json +++ b/packages/deployer/package.json @@ -53,7 +53,6 @@ "@types/require-from-string": "^1.2.0", "@types/semver": "^5.5.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 7b32187c4..f1cf56416 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, ContractDirectory, DeployerOptions } from './utils/types'; +import { CliOptions, CompilerOptions, 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 { const opts: CompilerOptions = { - contractDirs: getContractDirectoriesFromList(argv.contractDirs), + contractsDir: argv.contractsDir, networkId: argv.networkId, optimizerEnabled: argv.shouldOptimize, artifactsDir: argv.artifactsDir, @@ -45,7 +45,7 @@ async function onDeployCommandAsync(argv: CliOptions): Promise { const web3Wrapper = new Web3Wrapper(provider); const networkId = await web3Wrapper.getNetworkIdAsync(); const compilerOpts: CompilerOptions = { - contractDirs: getContractDirectoriesFromList(argv.contractDirs), + contractsDir: argv.contractsDir, networkId, optimizerEnabled: argv.shouldOptimize, artifactsDir: argv.artifactsDir, @@ -67,29 +67,6 @@ async function onDeployCommandAsync(argv: CliOptions): Promise { const deployerArgs = deployerArgsString.split(','); await commands.deployAsync(argv.contract as string, deployerArgs, deployerOpts); } -/** - * 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 { - 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 @@ -101,7 +78,8 @@ function getContractsSetFromList(contracts: string): Set { } const contractsArray = contracts.split(','); _.forEach(contractsArray, contractName => { - specifiedContracts.add(contractName); + const fileName = `${contractName}${constants.SOLIDITY_FILE_EXTENSION}`; + specifiedContracts.add(fileName); }); return specifiedContracts; } @@ -126,11 +104,10 @@ function deployCommandBuilder(yargsInstance: any) { (() => { const identityCommandBuilder = _.identity; return yargs - .option('contract-dirs', { + .option('contracts-dir', { type: 'string', default: DEFAULT_CONTRACTS_DIR, - description: - "comma separated list of contract directories.\nTo avoid filename clashes, directories should be prefixed with a namespace as follows: 'namespace:/path/to/dir'.", + description: 'path of contracts directory to compile', }) .option('network-id', { type: 'number', diff --git a/packages/deployer/src/compiler.ts b/packages/deployer/src/compiler.ts index e3ecc6c72..ba360cb57 100644 --- a/packages/deployer/src/compiler.ts +++ b/packages/deployer/src/compiler.ts @@ -1,4 +1,4 @@ -import { AbiType, ContractAbi, MethodAbi } from '@0xproject/types'; +import { ContractAbi } from '@0xproject/types'; import { logUtils, promisify } from '@0xproject/utils'; import * as ethUtil from 'ethereumjs-util'; import * as fs from 'fs'; @@ -11,8 +11,6 @@ import solc = require('solc'); import { binPaths } from './solc/bin_paths'; import { - constructContractId, - constructUniqueSourceFileId, createDirIfDoesNotExistAsync, findImportIfExist, getContractArtifactIfExistsAsync, @@ -25,14 +23,11 @@ import { fsWrapper } from './utils/fs_wrapper'; import { CompilerOptions, ContractArtifact, - ContractDirectory, - ContractIdToSourceFileId, ContractNetworkData, ContractNetworks, - ContractSourceDataByFileId, + ContractSourceData, ContractSources, ContractSpecificSourceData, - FunctionNameToSeenCount, } from './utils/types'; import { utils } from './utils/utils'; @@ -44,22 +39,20 @@ const SOLC_BIN_DIR = path.join(__dirname, '..', '..', 'solc_bin'); * to artifact files. */ export class Compiler { - private _contractDirs: Set; + private _contractsDir: string; 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 = new Set(); - private _contractSourceDataByFileId: ContractSourceDataByFileId = {}; - + private _contractSourceData: ContractSourceData = {}; /** * Recursively retrieves Solidity source code from directory. * @param dirPath Directory to search. - * @param contractBaseDir Base contracts directory of search tree. - * @return Mapping of sourceFilePath to the contract source. + * @return Mapping of contract fileName to contract source. */ - private static async _getContractSourcesAsync(dirPath: string, contractBaseDir: string): Promise { + private static async _getContractSourcesAsync(dirPath: string): Promise { let dirContents: string[] = []; try { dirContents = await fsWrapper.readdirAsync(dirPath); @@ -75,18 +68,14 @@ export class Compiler { encoding: 'utf8', }; const source = await fsWrapper.readFileAsync(contentPath, opts); - 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...`); + sources[fileName] = source; + logUtils.log(`Reading ${fileName} source...`); } catch (err) { logUtils.log(`Could not find file at ${contentPath}`); } } else { try { - const nestedSources = await Compiler._getContractSourcesAsync(contentPath, contractBaseDir); + const nestedSources = await Compiler._getContractSourcesAsync(contentPath); sources = { ...sources, ...nestedSources, @@ -104,7 +93,7 @@ export class Compiler { * @return An instance of the Compiler class. */ constructor(opts: CompilerOptions) { - this._contractDirs = opts.contractDirs; + this._contractsDir = opts.contractsDir; this._networkId = opts.networkId; this._optimizerEnabled = opts.optimizerEnabled; this._artifactsDir = opts.artifactsDir; @@ -116,49 +105,25 @@ export class Compiler { public async compileAsync(): Promise { await createDirIfDoesNotExistAsync(this._artifactsDir); await createDirIfDoesNotExistAsync(SOLC_BIN_DIR); - 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; - }); - } + this._contractSources = await Compiler._getContractSourcesAsync(this._contractsDir); _.forIn(this._contractSources, this._setContractSpecificSourceData.bind(this)); - const specifiedContractIds = this._specifiedContracts.has(ALL_CONTRACTS_IDENTIFIER) - ? _.keys(contractIdToSourceFileId) + const fileNames = this._specifiedContracts.has(ALL_CONTRACTS_IDENTIFIER) + ? _.keys(this._contractSources) : Array.from(this._specifiedContracts.values()); - await Promise.all( - _.map(specifiedContractIds, async contractId => - this._compileContractAsync(contractIdToSourceFileId[contractId]), - ), - ); + for (const fileName of fileNames) { + await this._compileContractAsync(fileName); + } } /** * Compiles contract and saves artifact to artifactsDir. - * @param sourceFileId Unique ID of the source file. + * @param fileName Name of contract with '.sol' extension. */ - private async _compileContractAsync(sourceFileId: string): Promise { + private async _compileContractAsync(fileName: string): Promise { if (_.isUndefined(this._contractSources)) { throw new Error('Contract sources not yet initialized'); } - 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 contractSpecificSourceData = this._contractSourceData[fileName]; + const currentArtifactIfExists = await getContractArtifactIfExistsAsync(this._artifactsDir, fileName); const sourceHash = `0x${contractSpecificSourceData.sourceHash.toString('hex')}`; const sourceTreeHash = `0x${contractSpecificSourceData.sourceTreeHash.toString('hex')}`; @@ -197,17 +162,16 @@ export class Compiler { } const solcInstance = solc.setupMethods(requireFromString(solcjs, compilerBinFilename)); - logUtils.log(`Compiling ${sourceFileId} with Solidity v${solcVersion}...`); - const source = this._contractSources[sourceFileId]; + logUtils.log(`Compiling ${fileName} with Solidity v${solcVersion}...`); + const source = this._contractSources[fileName]; const input = { - [sourceFileId]: source, + [fileName]: source, }; const sourcesToCompile = { sources: input, }; - const compiled = solcInstance.compile(sourcesToCompile, Number(this._optimizerEnabled), importPath => - findImportIfExist(this._contractSources, sourceFileId, importPath), + findImportIfExist(this._contractSources, importPath), ); if (!_.isUndefined(compiled.errors)) { @@ -229,11 +193,11 @@ export class Compiler { }); } } - const contractName = path.basename(sourceFileId, constants.SOLIDITY_FILE_EXTENSION); - const contractIdentifier = `${sourceFileId}:${contractName}`; + const contractName = path.basename(fileName, constants.SOLIDITY_FILE_EXTENSION); + const contractIdentifier = `${fileName}:${contractName}`; if (_.isUndefined(compiled.contracts[contractIdentifier])) { throw new Error( - `Contract ${contractName} not found in ${sourceFileId}. Please make sure your contract has the same name as it's file name`, + `Contract ${contractName} not found in ${fileName}. Please make sure your contract has the same name as it's file name`, ); } const abi: ContractAbi = JSON.parse(compiled.contracts[contractIdentifier].interface); @@ -243,7 +207,6 @@ 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, @@ -280,30 +243,28 @@ export class Compiler { const artifactString = utils.stringifyWithFormatting(newArtifact); const currentArtifactPath = `${this._artifactsDir}/${contractName}.json`; await fsWrapper.writeFileAsync(currentArtifactPath, artifactString); - logUtils.log(`${sourceFileId} artifact saved!`); + logUtils.log(`${fileName} 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, fileId: string): void { - if (!_.isUndefined(this._contractSourceDataByFileId[fileId])) { + private _setContractSpecificSourceData(source: string, fileName: string): void { + if (!_.isUndefined(this._contractSourceData[fileName])) { return; } const sourceHash = ethUtil.sha3(source); const solcVersionRange = parseSolidityVersionRange(source); - const dependencies = parseDependencies(source, fileId); - const sourceTreeHash = this._getSourceTreeHash(fileId, sourceHash, dependencies); - this._contractSourceDataByFileId[fileId] = { + const dependencies = parseDependencies(source); + const sourceTreeHash = this._getSourceTreeHash(fileName, sourceHash, dependencies); + this._contractSourceData[fileName] = { dependencies, solcVersionRange, sourceHash, sourceTreeHash, }; } - /** * Gets the source tree hash for a file and its dependencies. * @param fileName Name of contract file. @@ -315,7 +276,7 @@ export class Compiler { const dependencySourceTreeHashes = _.map(dependencies, dependency => { const source = this._contractSources[dependency]; this._setContractSpecificSourceData(source, dependency); - const sourceData = this._contractSourceDataByFileId[dependency]; + const sourceData = this._contractSourceData[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 600495693..d5137d394 100644 --- a/packages/deployer/src/utils/compiler.ts +++ b/packages/deployer/src/utils/compiler.ts @@ -1,4 +1,3 @@ -import { AbiType, ContractAbi, MethodAbi } from '@0xproject/types'; import { logUtils } from '@0xproject/utils'; import * as _ from 'lodash'; import * as path from 'path'; @@ -6,48 +5,8 @@ import * as solc from 'solc'; import { constants } from './constants'; import { fsWrapper } from './fs_wrapper'; -import { ContractArtifact, ContractSources, FunctionNameToSeenCount } from './types'; +import { ContractArtifact, ContractSources } 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. @@ -123,10 +82,9 @@ 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, sourceFileId: string): string[] { +export function parseDependencies(source: string): string[] { // TODO: Use a proper parser const IMPORT_REGEX = /(import\s)/; const DEPENDENCY_PATH_REGEX = /"([^"]+)"/; // Source: https://github.com/BlockChainCompany/soljitsu/blob/master/lib/shared.js @@ -137,8 +95,8 @@ export function parseDependencies(source: string, sourceFileId: string): string[ const dependencyMatch = line.match(DEPENDENCY_PATH_REGEX); if (!_.isNull(dependencyMatch)) { const dependencyPath = dependencyMatch[1]; - const dependencyId = constructDependencyFileId(dependencyPath, sourceFileId); - dependencies.push(dependencyId); + const basenName = path.basename(dependencyPath); + dependencies.push(basenName); } } }); @@ -149,19 +107,14 @@ export function parseDependencies(source: string, sourceFileId: string): string[ * Callback to resolve dependencies with `solc.compile`. * Throws error if contractSources not yet initialized. * @param contractSources Source codes of contracts. - * @param sourceFileId ID of the source file. - * @param importPath Path of dependency source file. + * @param importPath Path to an imported dependency. * @return Import contents object containing source code of dependency. */ -export function findImportIfExist( - contractSources: ContractSources, - sourceFileId: string, - importPath: string, -): solc.ImportContents { - const dependencyFileId = constructDependencyFileId(importPath, sourceFileId); - const source = contractSources[dependencyFileId]; +export function findImportIfExist(contractSources: ContractSources, importPath: string): solc.ImportContents { + const fileName = path.basename(importPath); + const source = contractSources[fileName]; if (_.isUndefined(source)) { - throw new Error(`Contract source not found for ${dependencyFileId}`); + throw new Error(`Contract source not found for ${fileName}`); } const importContents: solc.ImportContents = { contents: source, diff --git a/packages/deployer/src/utils/contract.ts b/packages/deployer/src/utils/contract.ts index e8dd5218a..9b7baac11 100644 --- a/packages/deployer/src/utils/contract.ts +++ b/packages/deployer/src/utils/contract.ts @@ -1,9 +1,11 @@ import { schemas, SchemaValidator } from '@0xproject/json-schemas'; -import { AbiType, ContractAbi, EventAbi, FunctionAbi, MethodAbi, TxData } from '@0xproject/types'; +import { 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 806efbbca..4f62662e1 100644 --- a/packages/deployer/src/utils/encoder.ts +++ b/packages/deployer/src/utils/encoder.ts @@ -1,7 +1,9 @@ -import { AbiDefinition, AbiType, ContractAbi, DataItem } from '@0xproject/types'; +import { AbiDefinition, 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 1a866b873..7d131f5ce 100644 --- a/packages/deployer/src/utils/types.ts +++ b/packages/deployer/src/utils/types.ts @@ -18,11 +18,6 @@ export interface ContractNetworks { [key: number]: ContractNetworkData; } -export interface ContractDirectory { - path: string; - namespace: string; -} - export interface ContractNetworkData { solc_version: string; optimizer_enabled: boolean; @@ -45,7 +40,7 @@ export interface SolcErrors { export interface CliOptions extends yargs.Arguments { artifactsDir: string; - contractDirs: string; + contractsDir: string; jsonrpcUrl: string; networkId: number; shouldOptimize: boolean; @@ -56,7 +51,7 @@ export interface CliOptions extends yargs.Arguments { } export interface CompilerOptions { - contractDirs: Set; + contractsDir: string; networkId: number; optimizerEnabled: boolean; artifactsDir: string; @@ -83,11 +78,7 @@ export interface ContractSources { [key: string]: string; } -export interface ContractIdToSourceFileId { - [key: string]: string; -} - -export interface ContractSourceDataByFileId { +export interface ContractSourceData { [key: string]: ContractSpecificSourceData; } @@ -107,8 +98,4 @@ 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 817a3b3f9..b03ae7935 100644 --- a/packages/deployer/test/compiler_test.ts +++ b/packages/deployer/test/compiler_test.ts @@ -3,13 +3,7 @@ import 'mocha'; import { Compiler } from '../src/compiler'; import { fsWrapper } from '../src/utils/fs_wrapper'; -import { - CompilerOptions, - ContractArtifact, - ContractDirectory, - ContractNetworkData, - DoneCallback, -} from '../src/utils/types'; +import { CompilerOptions, ContractArtifact, ContractNetworkData, DoneCallback } from '../src/utils/types'; import { exchange_binary } from './fixtures/exchange_bin'; import { constants } from './util/constants'; @@ -19,15 +13,11 @@ const expect = chai.expect; describe('#Compiler', function() { this.timeout(constants.timeoutMs); const artifactsDir = `${__dirname}/fixtures/artifacts`; - const mainContractDir: ContractDirectory = { path: `${__dirname}/fixtures/contracts/main`, namespace: 'main' }; - const baseContractDir: ContractDirectory = { path: `${__dirname}/fixtures/contracts/base`, namespace: 'base' }; - const contractDirs: Set = new Set(); - contractDirs.add(mainContractDir); - contractDirs.add(baseContractDir); + const contractsDir = `${__dirname}/fixtures/contracts`; const exchangeArtifactPath = `${artifactsDir}/Exchange.json`; const compilerOpts: CompilerOptions = { artifactsDir, - contractDirs, + contractsDir, 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 5377d3308..246304858 100644 --- a/packages/deployer/test/compiler_utils_test.ts +++ b/packages/deployer/test/compiler_utils_test.ts @@ -47,34 +47,28 @@ describe('Compiler utils', () => { }); describe('#parseDependencies', () => { it('correctly parses Exchange dependencies', async () => { - const exchangeSource = await fsWrapper.readFileAsync(`${__dirname}/fixtures/contracts/main/Exchange.sol`, { + const exchangeSource = await fsWrapper.readFileAsync(`${__dirname}/fixtures/contracts/Exchange.sol`, { encoding: 'utf8', }); - const sourceFileId = '/main/Exchange.sol'; - expect(parseDependencies(exchangeSource, sourceFileId)).to.be.deep.equal([ - '/main/TokenTransferProxy.sol', - '/base/Token.sol', - '/base/SafeMath.sol', + expect(parseDependencies(exchangeSource)).to.be.deep.equal([ + 'TokenTransferProxy.sol', + 'Token.sol', + 'SafeMath.sol', ]); }); it('correctly parses TokenTransferProxy dependencies', async () => { const exchangeSource = await fsWrapper.readFileAsync( - `${__dirname}/fixtures/contracts/main/TokenTransferProxy.sol`, + `${__dirname}/fixtures/contracts/TokenTransferProxy.sol`, { encoding: 'utf8', }, ); - const sourceFileId = '/main/TokenTransferProxy.sol'; - expect(parseDependencies(exchangeSource, sourceFileId)).to.be.deep.equal([ - '/base/Token.sol', - '/base/Ownable.sol', - ]); + expect(parseDependencies(exchangeSource)).to.be.deep.equal(['Token.sol', '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";`; - const sourceFileId = '/main/TokenTransferProxy.sol'; - expect(parseDependencies(contractWithCommentedOutDependencies, sourceFileId)).to.be.deep.equal([]); + expect(parseDependencies(contractWithCommentedOutDependencies)).to.be.deep.equal([]); }); }); }); diff --git a/packages/deployer/test/deployer_test.ts b/packages/deployer/test/deployer_test.ts index a213932f9..238624220 100644 --- a/packages/deployer/test/deployer_test.ts +++ b/packages/deployer/test/deployer_test.ts @@ -4,13 +4,7 @@ import 'mocha'; import { Compiler } from '../src/compiler'; import { Deployer } from '../src/deployer'; import { fsWrapper } from '../src/utils/fs_wrapper'; -import { - CompilerOptions, - ContractArtifact, - ContractDirectory, - ContractNetworkData, - DoneCallback, -} from '../src/utils/types'; +import { CompilerOptions, ContractArtifact, ContractNetworkData, DoneCallback } from '../src/utils/types'; import { constructor_args, exchange_binary } from './fixtures/exchange_bin'; import { constants } from './util/constants'; @@ -20,15 +14,11 @@ 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 = new Set(); - contractDirs.add(mainContractDir); - contractDirs.add(baseContractDir); const compilerOpts: CompilerOptions = { artifactsDir, - contractDirs, + contractsDir, 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/Exchange.sol new file mode 100644 index 000000000..1b6819700 --- /dev/null +++ b/packages/deployer/test/fixtures/contracts/Exchange.sol @@ -0,0 +1,602 @@ +/* + + Copyright 2017 ZeroEx Intl. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +pragma solidity 0.4.14; + +import "./TokenTransferProxy.sol"; +import "./base/Token.sol"; +import "./base/SafeMath.sol"; + +/// @title Exchange - Facilitates exchange of ERC20 tokens. +/// @author Amir Bandeali - , Will Warren - +contract Exchange is SafeMath { + + // Error Codes + enum Errors { + ORDER_EXPIRED, // Order has already expired + ORDER_FULLY_FILLED_OR_CANCELLED, // Order has already been fully filled or cancelled + ROUNDING_ERROR_TOO_LARGE, // Rounding error too large + INSUFFICIENT_BALANCE_OR_ALLOWANCE // Insufficient balance or allowance for token transfer + } + + string constant public VERSION = "1.0.0"; + uint16 constant public EXTERNAL_QUERY_GAS_LIMIT = 4999; // Changes to state require at least 5000 gas + + address public ZRX_TOKEN_CONTRACT; + address public TOKEN_TRANSFER_PROXY_CONTRACT; + + // Mappings of orderHash => amounts of takerTokenAmount filled or cancelled. + mapping (bytes32 => uint) public filled; + mapping (bytes32 => uint) public cancelled; + + event LogFill( + address indexed maker, + address taker, + address indexed feeRecipient, + address makerToken, + address takerToken, + uint filledMakerTokenAmount, + uint filledTakerTokenAmount, + uint paidMakerFee, + uint paidTakerFee, + bytes32 indexed tokens, // keccak256(makerToken, takerToken), allows subscribing to a token pair + bytes32 orderHash + ); + + event LogCancel( + address indexed maker, + address indexed feeRecipient, + address makerToken, + address takerToken, + uint cancelledMakerTokenAmount, + uint cancelledTakerTokenAmount, + bytes32 indexed tokens, + bytes32 orderHash + ); + + event LogError(uint8 indexed errorId, bytes32 indexed orderHash); + + struct Order { + address maker; + address taker; + address makerToken; + address takerToken; + address feeRecipient; + uint makerTokenAmount; + uint takerTokenAmount; + uint makerFee; + uint takerFee; + uint expirationTimestampInSec; + bytes32 orderHash; + } + + function Exchange(address _zrxToken, address _tokenTransferProxy) { + ZRX_TOKEN_CONTRACT = _zrxToken; + TOKEN_TRANSFER_PROXY_CONTRACT = _tokenTransferProxy; + } + + /* + * Core exchange functions + */ + + /// @dev Fills the input order. + /// @param orderAddresses Array of order's maker, taker, makerToken, takerToken, and feeRecipient. + /// @param orderValues Array of order's makerTokenAmount, takerTokenAmount, makerFee, takerFee, expirationTimestampInSec, and salt. + /// @param fillTakerTokenAmount Desired amount of takerToken to fill. + /// @param shouldThrowOnInsufficientBalanceOrAllowance Test if transfer will fail before attempting. + /// @param v ECDSA signature parameter v. + /// @param r ECDSA signature parameters r. + /// @param s ECDSA signature parameters s. + /// @return Total amount of takerToken filled in trade. + function fillOrder( + address[5] orderAddresses, + uint[6] orderValues, + uint fillTakerTokenAmount, + bool shouldThrowOnInsufficientBalanceOrAllowance, + uint8 v, + bytes32 r, + bytes32 s) + public + returns (uint filledTakerTokenAmount) + { + Order memory order = Order({ + maker: orderAddresses[0], + taker: orderAddresses[1], + makerToken: orderAddresses[2], + takerToken: orderAddresses[3], + feeRecipient: orderAddresses[4], + makerTokenAmount: orderValues[0], + takerTokenAmount: orderValues[1], + makerFee: orderValues[2], + takerFee: orderValues[3], + expirationTimestampInSec: orderValues[4], + orderHash: getOrderHash(orderAddresses, orderValues) + }); + + require(order.taker == address(0) || order.taker == msg.sender); + require(order.makerTokenAmount > 0 && order.takerTokenAmount > 0 && fillTakerTokenAmount > 0); + require(isValidSignature( + order.maker, + order.orderHash, + v, + r, + s + )); + + if (block.timestamp >= order.expirationTimestampInSec) { + LogError(uint8(Errors.ORDER_EXPIRED), order.orderHash); + return 0; + } + + uint remainingTakerTokenAmount = safeSub(order.takerTokenAmount, getUnavailableTakerTokenAmount(order.orderHash)); + filledTakerTokenAmount = min256(fillTakerTokenAmount, remainingTakerTokenAmount); + if (filledTakerTokenAmount == 0) { + LogError(uint8(Errors.ORDER_FULLY_FILLED_OR_CANCELLED), order.orderHash); + return 0; + } + + if (isRoundingError(filledTakerTokenAmount, order.takerTokenAmount, order.makerTokenAmount)) { + LogError(uint8(Errors.ROUNDING_ERROR_TOO_LARGE), order.orderHash); + return 0; + } + + if (!shouldThrowOnInsufficientBalanceOrAllowance && !isTransferable(order, filledTakerTokenAmount)) { + LogError(uint8(Errors.INSUFFICIENT_BALANCE_OR_ALLOWANCE), order.orderHash); + return 0; + } + + uint filledMakerTokenAmount = getPartialAmount(filledTakerTokenAmount, order.takerTokenAmount, order.makerTokenAmount); + uint paidMakerFee; + uint paidTakerFee; + filled[order.orderHash] = safeAdd(filled[order.orderHash], filledTakerTokenAmount); + require(transferViaTokenTransferProxy( + order.makerToken, + order.maker, + msg.sender, + filledMakerTokenAmount + )); + require(transferViaTokenTransferProxy( + order.takerToken, + msg.sender, + order.maker, + filledTakerTokenAmount + )); + if (order.feeRecipient != address(0)) { + if (order.makerFee > 0) { + paidMakerFee = getPartialAmount(filledTakerTokenAmount, order.takerTokenAmount, order.makerFee); + require(transferViaTokenTransferProxy( + ZRX_TOKEN_CONTRACT, + order.maker, + order.feeRecipient, + paidMakerFee + )); + } + if (order.takerFee > 0) { + paidTakerFee = getPartialAmount(filledTakerTokenAmount, order.takerTokenAmount, order.takerFee); + require(transferViaTokenTransferProxy( + ZRX_TOKEN_CONTRACT, + msg.sender, + order.feeRecipient, + paidTakerFee + )); + } + } + + LogFill( + order.maker, + msg.sender, + order.feeRecipient, + order.makerToken, + order.takerToken, + filledMakerTokenAmount, + filledTakerTokenAmount, + paidMakerFee, + paidTakerFee, + keccak256(order.makerToken, order.takerToken), + order.orderHash + ); + return filledTakerTokenAmount; + } + + /// @dev Cancels the input order. + /// @param orderAddresses Array of order's maker, taker, makerToken, takerToken, and feeRecipient. + /// @param orderValues Array of order's makerTokenAmount, takerTokenAmount, makerFee, takerFee, expirationTimestampInSec, and salt. + /// @param cancelTakerTokenAmount Desired amount of takerToken to cancel in order. + /// @return Amount of takerToken cancelled. + function cancelOrder( + address[5] orderAddresses, + uint[6] orderValues, + uint cancelTakerTokenAmount) + public + returns (uint) + { + Order memory order = Order({ + maker: orderAddresses[0], + taker: orderAddresses[1], + makerToken: orderAddresses[2], + takerToken: orderAddresses[3], + feeRecipient: orderAddresses[4], + makerTokenAmount: orderValues[0], + takerTokenAmount: orderValues[1], + makerFee: orderValues[2], + takerFee: orderValues[3], + expirationTimestampInSec: orderValues[4], + orderHash: getOrderHash(orderAddresses, orderValues) + }); + + require(order.maker == msg.sender); + require(order.makerTokenAmount > 0 && order.takerTokenAmount > 0 && cancelTakerTokenAmount > 0); + + if (block.timestamp >= order.expirationTimestampInSec) { + LogError(uint8(Errors.ORDER_EXPIRED), order.orderHash); + return 0; + } + + uint remainingTakerTokenAmount = safeSub(order.takerTokenAmount, getUnavailableTakerTokenAmount(order.orderHash)); + uint cancelledTakerTokenAmount = min256(cancelTakerTokenAmount, remainingTakerTokenAmount); + if (cancelledTakerTokenAmount == 0) { + LogError(uint8(Errors.ORDER_FULLY_FILLED_OR_CANCELLED), order.orderHash); + return 0; + } + + cancelled[order.orderHash] = safeAdd(cancelled[order.orderHash], cancelledTakerTokenAmount); + + LogCancel( + order.maker, + order.feeRecipient, + order.makerToken, + order.takerToken, + getPartialAmount(cancelledTakerTokenAmount, order.takerTokenAmount, order.makerTokenAmount), + cancelledTakerTokenAmount, + keccak256(order.makerToken, order.takerToken), + order.orderHash + ); + return cancelledTakerTokenAmount; + } + + /* + * Wrapper functions + */ + + /// @dev Fills an order with specified parameters and ECDSA signature, throws if specified amount not filled entirely. + /// @param orderAddresses Array of order's maker, taker, makerToken, takerToken, and feeRecipient. + /// @param orderValues Array of order's makerTokenAmount, takerTokenAmount, makerFee, takerFee, expirationTimestampInSec, and salt. + /// @param fillTakerTokenAmount Desired amount of takerToken to fill. + /// @param v ECDSA signature parameter v. + /// @param r ECDSA signature parameters r. + /// @param s ECDSA signature parameters s. + function fillOrKillOrder( + address[5] orderAddresses, + uint[6] orderValues, + uint fillTakerTokenAmount, + uint8 v, + bytes32 r, + bytes32 s) + public + { + require(fillOrder( + orderAddresses, + orderValues, + fillTakerTokenAmount, + false, + v, + r, + s + ) == fillTakerTokenAmount); + } + + /// @dev Synchronously executes multiple fill orders in a single transaction. + /// @param orderAddresses Array of address arrays containing individual order addresses. + /// @param orderValues Array of uint arrays containing individual order values. + /// @param fillTakerTokenAmounts Array of desired amounts of takerToken to fill in orders. + /// @param shouldThrowOnInsufficientBalanceOrAllowance Test if transfers will fail before attempting. + /// @param v Array ECDSA signature v parameters. + /// @param r Array of ECDSA signature r parameters. + /// @param s Array of ECDSA signature s parameters. + function batchFillOrders( + address[5][] orderAddresses, + uint[6][] orderValues, + uint[] fillTakerTokenAmounts, + bool shouldThrowOnInsufficientBalanceOrAllowance, + uint8[] v, + bytes32[] r, + bytes32[] s) + public + { + for (uint i = 0; i < orderAddresses.length; i++) { + fillOrder( + orderAddresses[i], + orderValues[i], + fillTakerTokenAmounts[i], + shouldThrowOnInsufficientBalanceOrAllowance, + v[i], + r[i], + s[i] + ); + } + } + + /// @dev Synchronously executes multiple fillOrKill orders in a single transaction. + /// @param orderAddresses Array of address arrays containing individual order addresses. + /// @param orderValues Array of uint arrays containing individual order values. + /// @param fillTakerTokenAmounts Array of desired amounts of takerToken to fill in orders. + /// @param v Array ECDSA signature v parameters. + /// @param r Array of ECDSA signature r parameters. + /// @param s Array of ECDSA signature s parameters. + function batchFillOrKillOrders( + address[5][] orderAddresses, + uint[6][] orderValues, + uint[] fillTakerTokenAmounts, + uint8[] v, + bytes32[] r, + bytes32[] s) + public + { + for (uint i = 0; i < orderAddresses.length; i++) { + fillOrKillOrder( + orderAddresses[i], + orderValues[i], + fillTakerTokenAmounts[i], + v[i], + r[i], + s[i] + ); + } + } + + /// @dev Synchronously executes multiple fill orders in a single transaction until total fillTakerTokenAmount filled. + /// @param orderAddresses Array of address arrays containing individual order addresses. + /// @param orderValues Array of uint arrays containing individual order values. + /// @param fillTakerTokenAmount Desired total amount of takerToken to fill in orders. + /// @param shouldThrowOnInsufficientBalanceOrAllowance Test if transfers will fail before attempting. + /// @param v Array ECDSA signature v parameters. + /// @param r Array of ECDSA signature r parameters. + /// @param s Array of ECDSA signature s parameters. + /// @return Total amount of fillTakerTokenAmount filled in orders. + function fillOrdersUpTo( + address[5][] orderAddresses, + uint[6][] orderValues, + uint fillTakerTokenAmount, + bool shouldThrowOnInsufficientBalanceOrAllowance, + uint8[] v, + bytes32[] r, + bytes32[] s) + public + returns (uint) + { + uint filledTakerTokenAmount = 0; + for (uint i = 0; i < orderAddresses.length; i++) { + require(orderAddresses[i][3] == orderAddresses[0][3]); // takerToken must be the same for each order + filledTakerTokenAmount = safeAdd(filledTakerTokenAmount, fillOrder( + orderAddresses[i], + orderValues[i], + safeSub(fillTakerTokenAmount, filledTakerTokenAmount), + shouldThrowOnInsufficientBalanceOrAllowance, + v[i], + r[i], + s[i] + )); + if (filledTakerTokenAmount == fillTakerTokenAmount) break; + } + return filledTakerTokenAmount; + } + + /// @dev Synchronously cancels multiple orders in a single transaction. + /// @param orderAddresses Array of address arrays containing individual order addresses. + /// @param orderValues Array of uint arrays containing individual order values. + /// @param cancelTakerTokenAmounts Array of desired amounts of takerToken to cancel in orders. + function batchCancelOrders( + address[5][] orderAddresses, + uint[6][] orderValues, + uint[] cancelTakerTokenAmounts) + public + { + for (uint i = 0; i < orderAddresses.length; i++) { + cancelOrder( + orderAddresses[i], + orderValues[i], + cancelTakerTokenAmounts[i] + ); + } + } + + /* + * Constant public functions + */ + + /// @dev Calculates Keccak-256 hash of order with specified parameters. + /// @param orderAddresses Array of order's maker, taker, makerToken, takerToken, and feeRecipient. + /// @param orderValues Array of order's makerTokenAmount, takerTokenAmount, makerFee, takerFee, expirationTimestampInSec, and salt. + /// @return Keccak-256 hash of order. + function getOrderHash(address[5] orderAddresses, uint[6] orderValues) + public + constant + returns (bytes32) + { + return keccak256( + address(this), + orderAddresses[0], // maker + orderAddresses[1], // taker + orderAddresses[2], // makerToken + orderAddresses[3], // takerToken + orderAddresses[4], // feeRecipient + orderValues[0], // makerTokenAmount + orderValues[1], // takerTokenAmount + orderValues[2], // makerFee + orderValues[3], // takerFee + orderValues[4], // expirationTimestampInSec + orderValues[5] // salt + ); + } + + /// @dev Verifies that an order signature is valid. + /// @param signer address of signer. + /// @param hash Signed Keccak-256 hash. + /// @param v ECDSA signature parameter v. + /// @param r ECDSA signature parameters r. + /// @param s ECDSA signature parameters s. + /// @return Validity of order signature. + function isValidSignature( + address signer, + bytes32 hash, + uint8 v, + bytes32 r, + bytes32 s) + public + constant + returns (bool) + { + return signer == ecrecover( + keccak256("\x19Ethereum Signed Message:\n32", hash), + v, + r, + s + ); + } + + /// @dev Checks if rounding error > 0.1%. + /// @param numerator Numerator. + /// @param denominator Denominator. + /// @param target Value to multiply with numerator/denominator. + /// @return Rounding error is present. + function isRoundingError(uint numerator, uint denominator, uint target) + public + constant + returns (bool) + { + uint remainder = mulmod(target, numerator, denominator); + if (remainder == 0) return false; // No rounding error. + + uint errPercentageTimes1000000 = safeDiv( + safeMul(remainder, 1000000), + safeMul(numerator, target) + ); + return errPercentageTimes1000000 > 1000; + } + + /// @dev Calculates partial value given a numerator and denominator. + /// @param numerator Numerator. + /// @param denominator Denominator. + /// @param target Value to calculate partial of. + /// @return Partial value of target. + function getPartialAmount(uint numerator, uint denominator, uint target) + public + constant + returns (uint) + { + return safeDiv(safeMul(numerator, target), denominator); + } + + /// @dev Calculates the sum of values already filled and cancelled for a given order. + /// @param orderHash The Keccak-256 hash of the given order. + /// @return Sum of values already filled and cancelled. + function getUnavailableTakerTokenAmount(bytes32 orderHash) + public + constant + returns (uint) + { + return safeAdd(filled[orderHash], cancelled[orderHash]); + } + + + /* + * Internal functions + */ + + /// @dev Transfers a token using TokenTransferProxy transferFrom function. + /// @param token Address of token to transferFrom. + /// @param from Address transfering token. + /// @param to Address receiving token. + /// @param value Amount of token to transfer. + /// @return Success of token transfer. + function transferViaTokenTransferProxy( + address token, + address from, + address to, + uint value) + internal + returns (bool) + { + return TokenTransferProxy(TOKEN_TRANSFER_PROXY_CONTRACT).transferFrom(token, from, to, value); + } + + /// @dev Checks if any order transfers will fail. + /// @param order Order struct of params that will be checked. + /// @param fillTakerTokenAmount Desired amount of takerToken to fill. + /// @return Predicted result of transfers. + function isTransferable(Order order, uint fillTakerTokenAmount) + internal + constant // The called token contracts may attempt to change state, but will not be able to due to gas limits on getBalance and getAllowance. + returns (bool) + { + address taker = msg.sender; + uint fillMakerTokenAmount = getPartialAmount(fillTakerTokenAmount, order.takerTokenAmount, order.makerTokenAmount); + + if (order.feeRecipient != address(0)) { + bool isMakerTokenZRX = order.makerToken == ZRX_TOKEN_CONTRACT; + bool isTakerTokenZRX = order.takerToken == ZRX_TOKEN_CONTRACT; + uint paidMakerFee = getPartialAmount(fillTakerTokenAmount, order.takerTokenAmount, order.makerFee); + uint paidTakerFee = getPartialAmount(fillTakerTokenAmount, order.takerTokenAmount, order.takerFee); + uint requiredMakerZRX = isMakerTokenZRX ? safeAdd(fillMakerTokenAmount, paidMakerFee) : paidMakerFee; + uint requiredTakerZRX = isTakerTokenZRX ? safeAdd(fillTakerTokenAmount, paidTakerFee) : paidTakerFee; + + if ( getBalance(ZRX_TOKEN_CONTRACT, order.maker) < requiredMakerZRX + || getAllowance(ZRX_TOKEN_CONTRACT, order.maker) < requiredMakerZRX + || getBalance(ZRX_TOKEN_CONTRACT, taker) < requiredTakerZRX + || getAllowance(ZRX_TOKEN_CONTRACT, taker) < requiredTakerZRX + ) return false; + + if (!isMakerTokenZRX && ( getBalance(order.makerToken, order.maker) < fillMakerTokenAmount // Don't double check makerToken if ZRX + || getAllowance(order.makerToken, order.maker) < fillMakerTokenAmount) + ) return false; + if (!isTakerTokenZRX && ( getBalance(order.takerToken, taker) < fillTakerTokenAmount // Don't double check takerToken if ZRX + || getAllowance(order.takerToken, taker) < fillTakerTokenAmount) + ) return false; + } else if ( getBalance(order.makerToken, order.maker) < fillMakerTokenAmount + || getAllowance(order.makerToken, order.maker) < fillMakerTokenAmount + || getBalance(order.takerToken, taker) < fillTakerTokenAmount + || getAllowance(order.takerToken, taker) < fillTakerTokenAmount + ) return false; + + return true; + } + + /// @dev Get token balance of an address. + /// @param token Address of token. + /// @param owner Address of owner. + /// @return Token balance of owner. + function getBalance(address token, address owner) + internal + constant // The called token contract may attempt to change state, but will not be able to due to an added gas limit. + returns (uint) + { + return Token(token).balanceOf.gas(EXTERNAL_QUERY_GAS_LIMIT)(owner); // Limit gas to prevent reentrancy + } + + /// @dev Get allowance of token given to TokenTransferProxy by an address. + /// @param token Address of token. + /// @param owner Address of owner. + /// @return Allowance of token given to TokenTransferProxy by owner. + function getAllowance(address token, address owner) + internal + constant // The called token contract may attempt to change state, but will not be able to due to an added gas limit. + returns (uint) + { + return Token(token).allowance.gas(EXTERNAL_QUERY_GAS_LIMIT)(owner, TOKEN_TRANSFER_PROXY_CONTRACT); // Limit gas to prevent reentrancy + } +} diff --git a/packages/deployer/test/fixtures/contracts/TokenTransferProxy.sol b/packages/deployer/test/fixtures/contracts/TokenTransferProxy.sol new file mode 100644 index 000000000..90c8e7d66 --- /dev/null +++ b/packages/deployer/test/fixtures/contracts/TokenTransferProxy.sol @@ -0,0 +1,115 @@ +/* + + Copyright 2017 ZeroEx Intl. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +pragma solidity 0.4.14; + +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 - , Will Warren - +contract TokenTransferProxy is Ownable { + + /// @dev Only authorized addresses can invoke functions with this modifier. + modifier onlyAuthorized { + require(authorized[msg.sender]); + _; + } + + modifier targetAuthorized(address target) { + require(authorized[target]); + _; + } + + modifier targetNotAuthorized(address target) { + require(!authorized[target]); + _; + } + + mapping (address => bool) public authorized; + address[] public authorities; + + event LogAuthorizedAddressAdded(address indexed target, address indexed caller); + event LogAuthorizedAddressRemoved(address indexed target, address indexed caller); + + /* + * Public functions + */ + + /// @dev Authorizes an address. + /// @param target Address to authorize. + function addAuthorizedAddress(address target) + public + onlyOwner + targetNotAuthorized(target) + { + authorized[target] = true; + authorities.push(target); + LogAuthorizedAddressAdded(target, msg.sender); + } + + /// @dev Removes authorizion of an address. + /// @param target Address to remove authorization from. + function removeAuthorizedAddress(address target) + public + onlyOwner + targetAuthorized(target) + { + delete authorized[target]; + for (uint i = 0; i < authorities.length; i++) { + if (authorities[i] == target) { + authorities[i] = authorities[authorities.length - 1]; + authorities.length -= 1; + break; + } + } + LogAuthorizedAddressRemoved(target, msg.sender); + } + + /// @dev Calls into ERC20 Token contract, invoking transferFrom. + /// @param token Address of token to transfer. + /// @param from Address to transfer token from. + /// @param to Address to transfer token to. + /// @param value Amount of token to transfer. + /// @return Success of transfer. + function transferFrom( + address token, + address from, + address to, + uint value) + public + onlyAuthorized + returns (bool) + { + return Token(token).transferFrom(from, to, value); + } + + /* + * Public constant functions + */ + + /// @dev Gets all authorized addresses. + /// @return Array of authorized addresses. + function getAuthorizedAddresses() + public + constant + returns (address[]) + { + return authorities; + } +} diff --git a/packages/deployer/test/fixtures/contracts/main/Exchange.sol b/packages/deployer/test/fixtures/contracts/main/Exchange.sol deleted file mode 100644 index ea9ca3afa..000000000 --- a/packages/deployer/test/fixtures/contracts/main/Exchange.sol +++ /dev/null @@ -1,602 +0,0 @@ -/* - - 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. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - -*/ - -pragma solidity 0.4.14; - -import "./TokenTransferProxy.sol"; -import "/base/Token.sol"; -import "/base/SafeMath.sol"; - -/// @title Exchange - Facilitates exchange of ERC20 tokens. -/// @author Amir Bandeali - , Will Warren - -contract Exchange is SafeMath { - - // Error Codes - enum Errors { - ORDER_EXPIRED, // Order has already expired - ORDER_FULLY_FILLED_OR_CANCELLED, // Order has already been fully filled or cancelled - ROUNDING_ERROR_TOO_LARGE, // Rounding error too large - INSUFFICIENT_BALANCE_OR_ALLOWANCE // Insufficient balance or allowance for token transfer - } - - string constant public VERSION = "1.0.0"; - uint16 constant public EXTERNAL_QUERY_GAS_LIMIT = 4999; // Changes to state require at least 5000 gas - - address public ZRX_TOKEN_CONTRACT; - address public TOKEN_TRANSFER_PROXY_CONTRACT; - - // Mappings of orderHash => amounts of takerTokenAmount filled or cancelled. - mapping (bytes32 => uint) public filled; - mapping (bytes32 => uint) public cancelled; - - event LogFill( - address indexed maker, - address taker, - address indexed feeRecipient, - address makerToken, - address takerToken, - uint filledMakerTokenAmount, - uint filledTakerTokenAmount, - uint paidMakerFee, - uint paidTakerFee, - bytes32 indexed tokens, // keccak256(makerToken, takerToken), allows subscribing to a token pair - bytes32 orderHash - ); - - event LogCancel( - address indexed maker, - address indexed feeRecipient, - address makerToken, - address takerToken, - uint cancelledMakerTokenAmount, - uint cancelledTakerTokenAmount, - bytes32 indexed tokens, - bytes32 orderHash - ); - - event LogError(uint8 indexed errorId, bytes32 indexed orderHash); - - struct Order { - address maker; - address taker; - address makerToken; - address takerToken; - address feeRecipient; - uint makerTokenAmount; - uint takerTokenAmount; - uint makerFee; - uint takerFee; - uint expirationTimestampInSec; - bytes32 orderHash; - } - - function Exchange(address _zrxToken, address _tokenTransferProxy) { - ZRX_TOKEN_CONTRACT = _zrxToken; - TOKEN_TRANSFER_PROXY_CONTRACT = _tokenTransferProxy; - } - - /* - * Core exchange functions - */ - - /// @dev Fills the input order. - /// @param orderAddresses Array of order's maker, taker, makerToken, takerToken, and feeRecipient. - /// @param orderValues Array of order's makerTokenAmount, takerTokenAmount, makerFee, takerFee, expirationTimestampInSec, and salt. - /// @param fillTakerTokenAmount Desired amount of takerToken to fill. - /// @param shouldThrowOnInsufficientBalanceOrAllowance Test if transfer will fail before attempting. - /// @param v ECDSA signature parameter v. - /// @param r ECDSA signature parameters r. - /// @param s ECDSA signature parameters s. - /// @return Total amount of takerToken filled in trade. - function fillOrder( - address[5] orderAddresses, - uint[6] orderValues, - uint fillTakerTokenAmount, - bool shouldThrowOnInsufficientBalanceOrAllowance, - uint8 v, - bytes32 r, - bytes32 s) - public - returns (uint filledTakerTokenAmount) - { - Order memory order = Order({ - maker: orderAddresses[0], - taker: orderAddresses[1], - makerToken: orderAddresses[2], - takerToken: orderAddresses[3], - feeRecipient: orderAddresses[4], - makerTokenAmount: orderValues[0], - takerTokenAmount: orderValues[1], - makerFee: orderValues[2], - takerFee: orderValues[3], - expirationTimestampInSec: orderValues[4], - orderHash: getOrderHash(orderAddresses, orderValues) - }); - - require(order.taker == address(0) || order.taker == msg.sender); - require(order.makerTokenAmount > 0 && order.takerTokenAmount > 0 && fillTakerTokenAmount > 0); - require(isValidSignature( - order.maker, - order.orderHash, - v, - r, - s - )); - - if (block.timestamp >= order.expirationTimestampInSec) { - LogError(uint8(Errors.ORDER_EXPIRED), order.orderHash); - return 0; - } - - uint remainingTakerTokenAmount = safeSub(order.takerTokenAmount, getUnavailableTakerTokenAmount(order.orderHash)); - filledTakerTokenAmount = min256(fillTakerTokenAmount, remainingTakerTokenAmount); - if (filledTakerTokenAmount == 0) { - LogError(uint8(Errors.ORDER_FULLY_FILLED_OR_CANCELLED), order.orderHash); - return 0; - } - - if (isRoundingError(filledTakerTokenAmount, order.takerTokenAmount, order.makerTokenAmount)) { - LogError(uint8(Errors.ROUNDING_ERROR_TOO_LARGE), order.orderHash); - return 0; - } - - if (!shouldThrowOnInsufficientBalanceOrAllowance && !isTransferable(order, filledTakerTokenAmount)) { - LogError(uint8(Errors.INSUFFICIENT_BALANCE_OR_ALLOWANCE), order.orderHash); - return 0; - } - - uint filledMakerTokenAmount = getPartialAmount(filledTakerTokenAmount, order.takerTokenAmount, order.makerTokenAmount); - uint paidMakerFee; - uint paidTakerFee; - filled[order.orderHash] = safeAdd(filled[order.orderHash], filledTakerTokenAmount); - require(transferViaTokenTransferProxy( - order.makerToken, - order.maker, - msg.sender, - filledMakerTokenAmount - )); - require(transferViaTokenTransferProxy( - order.takerToken, - msg.sender, - order.maker, - filledTakerTokenAmount - )); - if (order.feeRecipient != address(0)) { - if (order.makerFee > 0) { - paidMakerFee = getPartialAmount(filledTakerTokenAmount, order.takerTokenAmount, order.makerFee); - require(transferViaTokenTransferProxy( - ZRX_TOKEN_CONTRACT, - order.maker, - order.feeRecipient, - paidMakerFee - )); - } - if (order.takerFee > 0) { - paidTakerFee = getPartialAmount(filledTakerTokenAmount, order.takerTokenAmount, order.takerFee); - require(transferViaTokenTransferProxy( - ZRX_TOKEN_CONTRACT, - msg.sender, - order.feeRecipient, - paidTakerFee - )); - } - } - - LogFill( - order.maker, - msg.sender, - order.feeRecipient, - order.makerToken, - order.takerToken, - filledMakerTokenAmount, - filledTakerTokenAmount, - paidMakerFee, - paidTakerFee, - keccak256(order.makerToken, order.takerToken), - order.orderHash - ); - return filledTakerTokenAmount; - } - - /// @dev Cancels the input order. - /// @param orderAddresses Array of order's maker, taker, makerToken, takerToken, and feeRecipient. - /// @param orderValues Array of order's makerTokenAmount, takerTokenAmount, makerFee, takerFee, expirationTimestampInSec, and salt. - /// @param cancelTakerTokenAmount Desired amount of takerToken to cancel in order. - /// @return Amount of takerToken cancelled. - function cancelOrder( - address[5] orderAddresses, - uint[6] orderValues, - uint cancelTakerTokenAmount) - public - returns (uint) - { - Order memory order = Order({ - maker: orderAddresses[0], - taker: orderAddresses[1], - makerToken: orderAddresses[2], - takerToken: orderAddresses[3], - feeRecipient: orderAddresses[4], - makerTokenAmount: orderValues[0], - takerTokenAmount: orderValues[1], - makerFee: orderValues[2], - takerFee: orderValues[3], - expirationTimestampInSec: orderValues[4], - orderHash: getOrderHash(orderAddresses, orderValues) - }); - - require(order.maker == msg.sender); - require(order.makerTokenAmount > 0 && order.takerTokenAmount > 0 && cancelTakerTokenAmount > 0); - - if (block.timestamp >= order.expirationTimestampInSec) { - LogError(uint8(Errors.ORDER_EXPIRED), order.orderHash); - return 0; - } - - uint remainingTakerTokenAmount = safeSub(order.takerTokenAmount, getUnavailableTakerTokenAmount(order.orderHash)); - uint cancelledTakerTokenAmount = min256(cancelTakerTokenAmount, remainingTakerTokenAmount); - if (cancelledTakerTokenAmount == 0) { - LogError(uint8(Errors.ORDER_FULLY_FILLED_OR_CANCELLED), order.orderHash); - return 0; - } - - cancelled[order.orderHash] = safeAdd(cancelled[order.orderHash], cancelledTakerTokenAmount); - - LogCancel( - order.maker, - order.feeRecipient, - order.makerToken, - order.takerToken, - getPartialAmount(cancelledTakerTokenAmount, order.takerTokenAmount, order.makerTokenAmount), - cancelledTakerTokenAmount, - keccak256(order.makerToken, order.takerToken), - order.orderHash - ); - return cancelledTakerTokenAmount; - } - - /* - * Wrapper functions - */ - - /// @dev Fills an order with specified parameters and ECDSA signature, throws if specified amount not filled entirely. - /// @param orderAddresses Array of order's maker, taker, makerToken, takerToken, and feeRecipient. - /// @param orderValues Array of order's makerTokenAmount, takerTokenAmount, makerFee, takerFee, expirationTimestampInSec, and salt. - /// @param fillTakerTokenAmount Desired amount of takerToken to fill. - /// @param v ECDSA signature parameter v. - /// @param r ECDSA signature parameters r. - /// @param s ECDSA signature parameters s. - function fillOrKillOrder( - address[5] orderAddresses, - uint[6] orderValues, - uint fillTakerTokenAmount, - uint8 v, - bytes32 r, - bytes32 s) - public - { - require(fillOrder( - orderAddresses, - orderValues, - fillTakerTokenAmount, - false, - v, - r, - s - ) == fillTakerTokenAmount); - } - - /// @dev Synchronously executes multiple fill orders in a single transaction. - /// @param orderAddresses Array of address arrays containing individual order addresses. - /// @param orderValues Array of uint arrays containing individual order values. - /// @param fillTakerTokenAmounts Array of desired amounts of takerToken to fill in orders. - /// @param shouldThrowOnInsufficientBalanceOrAllowance Test if transfers will fail before attempting. - /// @param v Array ECDSA signature v parameters. - /// @param r Array of ECDSA signature r parameters. - /// @param s Array of ECDSA signature s parameters. - function batchFillOrders( - address[5][] orderAddresses, - uint[6][] orderValues, - uint[] fillTakerTokenAmounts, - bool shouldThrowOnInsufficientBalanceOrAllowance, - uint8[] v, - bytes32[] r, - bytes32[] s) - public - { - for (uint i = 0; i < orderAddresses.length; i++) { - fillOrder( - orderAddresses[i], - orderValues[i], - fillTakerTokenAmounts[i], - shouldThrowOnInsufficientBalanceOrAllowance, - v[i], - r[i], - s[i] - ); - } - } - - /// @dev Synchronously executes multiple fillOrKill orders in a single transaction. - /// @param orderAddresses Array of address arrays containing individual order addresses. - /// @param orderValues Array of uint arrays containing individual order values. - /// @param fillTakerTokenAmounts Array of desired amounts of takerToken to fill in orders. - /// @param v Array ECDSA signature v parameters. - /// @param r Array of ECDSA signature r parameters. - /// @param s Array of ECDSA signature s parameters. - function batchFillOrKillOrders( - address[5][] orderAddresses, - uint[6][] orderValues, - uint[] fillTakerTokenAmounts, - uint8[] v, - bytes32[] r, - bytes32[] s) - public - { - for (uint i = 0; i < orderAddresses.length; i++) { - fillOrKillOrder( - orderAddresses[i], - orderValues[i], - fillTakerTokenAmounts[i], - v[i], - r[i], - s[i] - ); - } - } - - /// @dev Synchronously executes multiple fill orders in a single transaction until total fillTakerTokenAmount filled. - /// @param orderAddresses Array of address arrays containing individual order addresses. - /// @param orderValues Array of uint arrays containing individual order values. - /// @param fillTakerTokenAmount Desired total amount of takerToken to fill in orders. - /// @param shouldThrowOnInsufficientBalanceOrAllowance Test if transfers will fail before attempting. - /// @param v Array ECDSA signature v parameters. - /// @param r Array of ECDSA signature r parameters. - /// @param s Array of ECDSA signature s parameters. - /// @return Total amount of fillTakerTokenAmount filled in orders. - function fillOrdersUpTo( - address[5][] orderAddresses, - uint[6][] orderValues, - uint fillTakerTokenAmount, - bool shouldThrowOnInsufficientBalanceOrAllowance, - uint8[] v, - bytes32[] r, - bytes32[] s) - public - returns (uint) - { - uint filledTakerTokenAmount = 0; - for (uint i = 0; i < orderAddresses.length; i++) { - require(orderAddresses[i][3] == orderAddresses[0][3]); // takerToken must be the same for each order - filledTakerTokenAmount = safeAdd(filledTakerTokenAmount, fillOrder( - orderAddresses[i], - orderValues[i], - safeSub(fillTakerTokenAmount, filledTakerTokenAmount), - shouldThrowOnInsufficientBalanceOrAllowance, - v[i], - r[i], - s[i] - )); - if (filledTakerTokenAmount == fillTakerTokenAmount) break; - } - return filledTakerTokenAmount; - } - - /// @dev Synchronously cancels multiple orders in a single transaction. - /// @param orderAddresses Array of address arrays containing individual order addresses. - /// @param orderValues Array of uint arrays containing individual order values. - /// @param cancelTakerTokenAmounts Array of desired amounts of takerToken to cancel in orders. - function batchCancelOrders( - address[5][] orderAddresses, - uint[6][] orderValues, - uint[] cancelTakerTokenAmounts) - public - { - for (uint i = 0; i < orderAddresses.length; i++) { - cancelOrder( - orderAddresses[i], - orderValues[i], - cancelTakerTokenAmounts[i] - ); - } - } - - /* - * Constant public functions - */ - - /// @dev Calculates Keccak-256 hash of order with specified parameters. - /// @param orderAddresses Array of order's maker, taker, makerToken, takerToken, and feeRecipient. - /// @param orderValues Array of order's makerTokenAmount, takerTokenAmount, makerFee, takerFee, expirationTimestampInSec, and salt. - /// @return Keccak-256 hash of order. - function getOrderHash(address[5] orderAddresses, uint[6] orderValues) - public - constant - returns (bytes32) - { - return keccak256( - address(this), - orderAddresses[0], // maker - orderAddresses[1], // taker - orderAddresses[2], // makerToken - orderAddresses[3], // takerToken - orderAddresses[4], // feeRecipient - orderValues[0], // makerTokenAmount - orderValues[1], // takerTokenAmount - orderValues[2], // makerFee - orderValues[3], // takerFee - orderValues[4], // expirationTimestampInSec - orderValues[5] // salt - ); - } - - /// @dev Verifies that an order signature is valid. - /// @param signer address of signer. - /// @param hash Signed Keccak-256 hash. - /// @param v ECDSA signature parameter v. - /// @param r ECDSA signature parameters r. - /// @param s ECDSA signature parameters s. - /// @return Validity of order signature. - function isValidSignature( - address signer, - bytes32 hash, - uint8 v, - bytes32 r, - bytes32 s) - public - constant - returns (bool) - { - return signer == ecrecover( - keccak256("\x19Ethereum Signed Message:\n32", hash), - v, - r, - s - ); - } - - /// @dev Checks if rounding error > 0.1%. - /// @param numerator Numerator. - /// @param denominator Denominator. - /// @param target Value to multiply with numerator/denominator. - /// @return Rounding error is present. - function isRoundingError(uint numerator, uint denominator, uint target) - public - constant - returns (bool) - { - uint remainder = mulmod(target, numerator, denominator); - if (remainder == 0) return false; // No rounding error. - - uint errPercentageTimes1000000 = safeDiv( - safeMul(remainder, 1000000), - safeMul(numerator, target) - ); - return errPercentageTimes1000000 > 1000; - } - - /// @dev Calculates partial value given a numerator and denominator. - /// @param numerator Numerator. - /// @param denominator Denominator. - /// @param target Value to calculate partial of. - /// @return Partial value of target. - function getPartialAmount(uint numerator, uint denominator, uint target) - public - constant - returns (uint) - { - return safeDiv(safeMul(numerator, target), denominator); - } - - /// @dev Calculates the sum of values already filled and cancelled for a given order. - /// @param orderHash The Keccak-256 hash of the given order. - /// @return Sum of values already filled and cancelled. - function getUnavailableTakerTokenAmount(bytes32 orderHash) - public - constant - returns (uint) - { - return safeAdd(filled[orderHash], cancelled[orderHash]); - } - - - /* - * Internal functions - */ - - /// @dev Transfers a token using TokenTransferProxy transferFrom function. - /// @param token Address of token to transferFrom. - /// @param from Address transfering token. - /// @param to Address receiving token. - /// @param value Amount of token to transfer. - /// @return Success of token transfer. - function transferViaTokenTransferProxy( - address token, - address from, - address to, - uint value) - internal - returns (bool) - { - return TokenTransferProxy(TOKEN_TRANSFER_PROXY_CONTRACT).transferFrom(token, from, to, value); - } - - /// @dev Checks if any order transfers will fail. - /// @param order Order struct of params that will be checked. - /// @param fillTakerTokenAmount Desired amount of takerToken to fill. - /// @return Predicted result of transfers. - function isTransferable(Order order, uint fillTakerTokenAmount) - internal - constant // The called token contracts may attempt to change state, but will not be able to due to gas limits on getBalance and getAllowance. - returns (bool) - { - address taker = msg.sender; - uint fillMakerTokenAmount = getPartialAmount(fillTakerTokenAmount, order.takerTokenAmount, order.makerTokenAmount); - - if (order.feeRecipient != address(0)) { - bool isMakerTokenZRX = order.makerToken == ZRX_TOKEN_CONTRACT; - bool isTakerTokenZRX = order.takerToken == ZRX_TOKEN_CONTRACT; - uint paidMakerFee = getPartialAmount(fillTakerTokenAmount, order.takerTokenAmount, order.makerFee); - uint paidTakerFee = getPartialAmount(fillTakerTokenAmount, order.takerTokenAmount, order.takerFee); - uint requiredMakerZRX = isMakerTokenZRX ? safeAdd(fillMakerTokenAmount, paidMakerFee) : paidMakerFee; - uint requiredTakerZRX = isTakerTokenZRX ? safeAdd(fillTakerTokenAmount, paidTakerFee) : paidTakerFee; - - if ( getBalance(ZRX_TOKEN_CONTRACT, order.maker) < requiredMakerZRX - || getAllowance(ZRX_TOKEN_CONTRACT, order.maker) < requiredMakerZRX - || getBalance(ZRX_TOKEN_CONTRACT, taker) < requiredTakerZRX - || getAllowance(ZRX_TOKEN_CONTRACT, taker) < requiredTakerZRX - ) return false; - - if (!isMakerTokenZRX && ( getBalance(order.makerToken, order.maker) < fillMakerTokenAmount // Don't double check makerToken if ZRX - || getAllowance(order.makerToken, order.maker) < fillMakerTokenAmount) - ) return false; - if (!isTakerTokenZRX && ( getBalance(order.takerToken, taker) < fillTakerTokenAmount // Don't double check takerToken if ZRX - || getAllowance(order.takerToken, taker) < fillTakerTokenAmount) - ) return false; - } else if ( getBalance(order.makerToken, order.maker) < fillMakerTokenAmount - || getAllowance(order.makerToken, order.maker) < fillMakerTokenAmount - || getBalance(order.takerToken, taker) < fillTakerTokenAmount - || getAllowance(order.takerToken, taker) < fillTakerTokenAmount - ) return false; - - return true; - } - - /// @dev Get token balance of an address. - /// @param token Address of token. - /// @param owner Address of owner. - /// @return Token balance of owner. - function getBalance(address token, address owner) - internal - constant // The called token contract may attempt to change state, but will not be able to due to an added gas limit. - returns (uint) - { - return Token(token).balanceOf.gas(EXTERNAL_QUERY_GAS_LIMIT)(owner); // Limit gas to prevent reentrancy - } - - /// @dev Get allowance of token given to TokenTransferProxy by an address. - /// @param token Address of token. - /// @param owner Address of owner. - /// @return Allowance of token given to TokenTransferProxy by owner. - function getAllowance(address token, address owner) - internal - constant // The called token contract may attempt to change state, but will not be able to due to an added gas limit. - returns (uint) - { - return Token(token).allowance.gas(EXTERNAL_QUERY_GAS_LIMIT)(owner, TOKEN_TRANSFER_PROXY_CONTRACT); // Limit gas to prevent reentrancy - } -} diff --git a/packages/deployer/test/fixtures/contracts/main/TokenTransferProxy.sol b/packages/deployer/test/fixtures/contracts/main/TokenTransferProxy.sol deleted file mode 100644 index 99d16cb57..000000000 --- a/packages/deployer/test/fixtures/contracts/main/TokenTransferProxy.sol +++ /dev/null @@ -1,115 +0,0 @@ -/* - - 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. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - -*/ - -pragma solidity 0.4.14; - -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 - , Will Warren - -contract TokenTransferProxy is Ownable { - - /// @dev Only authorized addresses can invoke functions with this modifier. - modifier onlyAuthorized { - require(authorized[msg.sender]); - _; - } - - modifier targetAuthorized(address target) { - require(authorized[target]); - _; - } - - modifier targetNotAuthorized(address target) { - require(!authorized[target]); - _; - } - - mapping (address => bool) public authorized; - address[] public authorities; - - event LogAuthorizedAddressAdded(address indexed target, address indexed caller); - event LogAuthorizedAddressRemoved(address indexed target, address indexed caller); - - /* - * Public functions - */ - - /// @dev Authorizes an address. - /// @param target Address to authorize. - function addAuthorizedAddress(address target) - public - onlyOwner - targetNotAuthorized(target) - { - authorized[target] = true; - authorities.push(target); - LogAuthorizedAddressAdded(target, msg.sender); - } - - /// @dev Removes authorizion of an address. - /// @param target Address to remove authorization from. - function removeAuthorizedAddress(address target) - public - onlyOwner - targetAuthorized(target) - { - delete authorized[target]; - for (uint i = 0; i < authorities.length; i++) { - if (authorities[i] == target) { - authorities[i] = authorities[authorities.length - 1]; - authorities.length -= 1; - break; - } - } - LogAuthorizedAddressRemoved(target, msg.sender); - } - - /// @dev Calls into ERC20 Token contract, invoking transferFrom. - /// @param token Address of token to transfer. - /// @param from Address to transfer token from. - /// @param to Address to transfer token to. - /// @param value Amount of token to transfer. - /// @return Success of transfer. - function transferFrom( - address token, - address from, - address to, - uint value) - public - onlyAuthorized - returns (bool) - { - return Token(token).transferFrom(from, to, value); - } - - /* - * Public constant functions - */ - - /// @dev Gets all authorized addresses. - /// @return Array of authorized addresses. - function getAuthorizedAddresses() - public - constant - returns (address[]) - { - return authorities; - } -} -- cgit v1.2.3 From 4dd9f29769bea90a4b687be26b086164aaff685a Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Tue, 10 Apr 2018 14:06:43 +0200 Subject: Add ony abi-gen changes from Greg's PR --- packages/deployer/package.json | 1 + packages/deployer/src/utils/contract.ts | 4 +--- packages/deployer/src/utils/encoder.ts | 4 +--- 3 files changed, 3 insertions(+), 6 deletions(-) (limited to 'packages/deployer') diff --git a/packages/deployer/package.json b/packages/deployer/package.json index ef5c1cd16..6afaa13b3 100644 --- a/packages/deployer/package.json +++ b/packages/deployer/package.json @@ -53,6 +53,7 @@ "@types/require-from-string": "^1.2.0", "@types/semver": "^5.5.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/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[] = []; -- cgit v1.2.3 From 442017f93ad1fa5af7b751da7cfdda3deb0861ab Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Fri, 6 Apr 2018 18:37:48 +0200 Subject: Use solc.compileStandardWrapper --- packages/deployer/package.json | 1 + packages/deployer/src/cli.ts | 3 +- packages/deployer/src/compiler.ts | 117 ++++++++++++++++++++------------ packages/deployer/src/utils/compiler.ts | 18 +++-- packages/deployer/src/utils/types.ts | 7 +- 5 files changed, 88 insertions(+), 58 deletions(-) (limited to 'packages/deployer') diff --git a/packages/deployer/package.json b/packages/deployer/package.json index 6afaa13b3..3c71cd5ff 100644 --- a/packages/deployer/package.json +++ b/packages/deployer/package.json @@ -73,6 +73,7 @@ "@0xproject/utils": "^0.5.1", "@0xproject/web3-wrapper": "^0.6.0", "@types/yargs": "^11.0.0", + "chalk": "^2.3.0", "ethereumjs-util": "^5.1.1", "isomorphic-fetch": "^2.2.1", "lodash": "^4.17.4", diff --git a/packages/deployer/src/cli.ts b/packages/deployer/src/cli.ts index f1cf56416..7f1ae708a 100644 --- a/packages/deployer/src/cli.ts +++ b/packages/deployer/src/cli.ts @@ -78,8 +78,7 @@ function getContractsSetFromList(contracts: string): Set { } const contractsArray = contracts.split(','); _.forEach(contractsArray, contractName => { - const fileName = `${contractName}${constants.SOLIDITY_FILE_EXTENSION}`; - specifiedContracts.add(fileName); + specifiedContracts.add(contractName); }); return specifiedContracts; } diff --git a/packages/deployer/src/compiler.ts b/packages/deployer/src/compiler.ts index ba360cb57..ad35a7794 100644 --- a/packages/deployer/src/compiler.ts +++ b/packages/deployer/src/compiler.ts @@ -1,5 +1,6 @@ import { ContractAbi } from '@0xproject/types'; import { logUtils, promisify } from '@0xproject/utils'; +import chalk from 'chalk'; import * as ethUtil from 'ethereumjs-util'; import * as fs from 'fs'; import 'isomorphic-fetch'; @@ -62,14 +63,19 @@ export class Compiler { let sources: ContractSources = {}; for (const fileName of dirContents) { const contentPath = `${dirPath}/${fileName}`; + const contractName = path.basename(fileName, constants.SOLIDITY_FILE_EXTENSION); + const absoluteFilePath = path.resolve(contentPath); if (path.extname(fileName) === constants.SOLIDITY_FILE_EXTENSION) { try { const opts = { encoding: 'utf8', }; const source = await fsWrapper.readFileAsync(contentPath, opts); - sources[fileName] = source; - logUtils.log(`Reading ${fileName} source...`); + sources[contractName] = { + source, + absoluteFilePath, + }; + logUtils.log(`Reading ${contractName} source...`); } catch (err) { logUtils.log(`Could not find file at ${contentPath}`); } @@ -106,24 +112,27 @@ export class Compiler { await createDirIfDoesNotExistAsync(this._artifactsDir); await createDirIfDoesNotExistAsync(SOLC_BIN_DIR); this._contractSources = await Compiler._getContractSourcesAsync(this._contractsDir); - _.forIn(this._contractSources, this._setContractSpecificSourceData.bind(this)); - const fileNames = this._specifiedContracts.has(ALL_CONTRACTS_IDENTIFIER) + for (const contractName of _.keys(this._contractSources)) { + const contractSource = this._contractSources[contractName]; + this._setContractSpecificSourceData(contractSource.source, contractName); + } + const contractNames = this._specifiedContracts.has(ALL_CONTRACTS_IDENTIFIER) ? _.keys(this._contractSources) : Array.from(this._specifiedContracts.values()); - for (const fileName of fileNames) { - await this._compileContractAsync(fileName); + for (const contractName of contractNames) { + await this._compileContractAsync(contractName); } } /** * Compiles contract and saves artifact to artifactsDir. * @param fileName Name of contract with '.sol' extension. */ - private async _compileContractAsync(fileName: string): Promise { + private async _compileContractAsync(contractName: string): Promise { if (_.isUndefined(this._contractSources)) { throw new Error('Contract sources not yet initialized'); } - const contractSpecificSourceData = this._contractSourceData[fileName]; - const currentArtifactIfExists = await getContractArtifactIfExistsAsync(this._artifactsDir, fileName); + const contractSpecificSourceData = this._contractSourceData[contractName]; + const currentArtifactIfExists = await getContractArtifactIfExistsAsync(this._artifactsDir, contractName); const sourceHash = `0x${contractSpecificSourceData.sourceHash.toString('hex')}`; const sourceTreeHash = `0x${contractSpecificSourceData.sourceTreeHash.toString('hex')}`; @@ -162,49 +171,69 @@ export class Compiler { } const solcInstance = solc.setupMethods(requireFromString(solcjs, compilerBinFilename)); - logUtils.log(`Compiling ${fileName} with Solidity v${solcVersion}...`); - const source = this._contractSources[fileName]; - const input = { - [fileName]: source, - }; - const sourcesToCompile = { - sources: input, + logUtils.log(`Compiling ${contractName} with Solidity v${solcVersion}...`); + const source = this._contractSources[contractName].source; + const absoluteFilePath = this._contractSources[contractName].absoluteFilePath; + const standardInput: solc.StandardInput = { + language: 'Solidity', + sources: { + [absoluteFilePath]: { + urls: [`file://${absoluteFilePath}`], + }, + }, + settings: { + optimizer: { + enabled: this._optimizerEnabled, + }, + outputSelection: { + '*': { + '*': [ + 'abi', + 'evm.bytecode.object', + 'evm.bytecode.sourceMap', + 'evm.deployedBytecode.object', + 'evm.deployedBytecode.sourceMap', + ], + }, + }, + }, }; - const compiled = solcInstance.compile(sourcesToCompile, Number(this._optimizerEnabled), importPath => - findImportIfExist(this._contractSources, importPath), + const compiled: solc.StandardOutput = JSON.parse( + solcInstance.compileStandardWrapper(JSON.stringify(standardInput), importPath => + findImportIfExist(this._contractSources, importPath), + ), ); if (!_.isUndefined(compiled.errors)) { - const SOLIDITY_WARNING_PREFIX = 'Warning'; - const isError = (errorOrWarning: string) => !errorOrWarning.includes(SOLIDITY_WARNING_PREFIX); - const isWarning = (errorOrWarning: string) => errorOrWarning.includes(SOLIDITY_WARNING_PREFIX); + const SOLIDITY_WARNING = 'warning'; + const isError = (entry: any) => entry.severity !== SOLIDITY_WARNING; + const isWarning = (entry: any) => entry.severity === SOLIDITY_WARNING; const errors = _.filter(compiled.errors, isError); const warnings = _.filter(compiled.errors, isWarning); if (!_.isEmpty(errors)) { - errors.forEach(errMsg => { - const normalizedErrMsg = getNormalizedErrMsg(errMsg); - logUtils.log(normalizedErrMsg); + errors.forEach(error => { + const normalizedErrMsg = getNormalizedErrMsg(error.formattedMessage); + logUtils.log(chalk.red(normalizedErrMsg)); }); process.exit(1); } else { - warnings.forEach(errMsg => { - const normalizedErrMsg = getNormalizedErrMsg(errMsg); - logUtils.log(normalizedErrMsg); + warnings.forEach(warning => { + const normalizedWarningMsg = getNormalizedErrMsg(warning.formattedMessage); + logUtils.log(chalk.yellow(normalizedWarningMsg)); }); } } - const contractName = path.basename(fileName, constants.SOLIDITY_FILE_EXTENSION); - const contractIdentifier = `${fileName}:${contractName}`; - if (_.isUndefined(compiled.contracts[contractIdentifier])) { + const compiledData = compiled.contracts[absoluteFilePath][contractName]; + if (_.isUndefined(compiledData)) { 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 ${absoluteFilePath}. Please make sure your contract has the same name as it's file name`, ); } - const abi: ContractAbi = JSON.parse(compiled.contracts[contractIdentifier].interface); - const bytecode = `0x${compiled.contracts[contractIdentifier].bytecode}`; - const runtimeBytecode = `0x${compiled.contracts[contractIdentifier].runtimeBytecode}`; - const sourceMap = compiled.contracts[contractIdentifier].srcmap; - const sourceMapRuntime = compiled.contracts[contractIdentifier].srcmapRuntime; + const abi: ContractAbi = compiledData.abi; + const bytecode = `0x${compiledData.evm.bytecode.object}`; + const runtimeBytecode = `0x${compiledData.evm.deployedBytecode.object}`; + const sourceMap = compiledData.evm.bytecode.sourceMap; + const sourceMapRuntime = compiledData.evm.deployedBytecode.sourceMap; const sources = _.keys(compiled.sources); const updated_at = Date.now(); const contractNetworkData: ContractNetworkData = { @@ -243,22 +272,22 @@ 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(`${contractName} artifact saved!`); } /** * Gets contract dependendencies and keccak256 hash from source. * @param source Source code of contract. * @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, contractName: string): void { + if (!_.isUndefined(this._contractSourceData[contractName])) { 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 sourceTreeHash = this._getSourceTreeHash(sourceHash, dependencies); + this._contractSourceData[contractName] = { dependencies, solcVersionRange, sourceHash, @@ -269,15 +298,15 @@ export class Compiler { * Gets the source tree hash for a file and its dependencies. * @param fileName Name of contract file. */ - private _getSourceTreeHash(fileName: string, sourceHash: Buffer, dependencies: string[]): Buffer { + private _getSourceTreeHash(sourceHash: Buffer, dependencies: string[]): Buffer { if (dependencies.length === 0) { return sourceHash; } else { const dependencySourceTreeHashes = _.map(dependencies, dependency => { - const source = this._contractSources[dependency]; + const source = this._contractSources[dependency].source; this._setContractSpecificSourceData(source, dependency); const sourceData = this._contractSourceData[dependency]; - return this._getSourceTreeHash(dependency, sourceData.sourceHash, sourceData.dependencies); + return this._getSourceTreeHash(sourceData.sourceHash, sourceData.dependencies); }); const sourceTreeHashesBuffer = Buffer.concat([sourceHash, ...dependencySourceTreeHashes]); const sourceTreeHash = ethUtil.sha3(sourceTreeHashesBuffer); diff --git a/packages/deployer/src/utils/compiler.ts b/packages/deployer/src/utils/compiler.ts index d5137d394..b83be221a 100644 --- a/packages/deployer/src/utils/compiler.ts +++ b/packages/deployer/src/utils/compiler.ts @@ -10,15 +10,14 @@ import { ContractArtifact, ContractSources } from './types'; /** * Gets contract data on network or returns if an artifact does not exist. * @param artifactsDir Path to the artifacts directory. - * @param fileName Name of contract file. + * @param contractName Name of contract. * @return Contract data on network or undefined. */ export async function getContractArtifactIfExistsAsync( artifactsDir: string, - fileName: string, + contractName: string, ): Promise { let contractArtifact; - const contractName = path.basename(fileName, constants.SOLIDITY_FILE_EXTENSION); const currentArtifactPath = `${artifactsDir}/${contractName}.json`; try { const opts = { @@ -28,7 +27,7 @@ export async function getContractArtifactIfExistsAsync( contractArtifact = JSON.parse(contractArtifactString); return contractArtifact; } catch (err) { - logUtils.log(`Artifact for ${fileName} does not exist`); + logUtils.log(`Artifact for ${contractName} does not exist`); return undefined; } } @@ -95,8 +94,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 contractName = path.basename(dependencyPath, constants.SOLIDITY_FILE_EXTENSION); + dependencies.push(contractName); } } }); @@ -105,16 +104,15 @@ 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. * @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]; + const contractName = path.basename(importPath, constants.SOLIDITY_FILE_EXTENSION); + const source = contractSources[contractName].source; if (_.isUndefined(source)) { - throw new Error(`Contract source not found for ${fileName}`); + throw new Error(`Contract source not found for ${contractName}`); } const importContents: solc.ImportContents = { contents: source, diff --git a/packages/deployer/src/utils/types.ts b/packages/deployer/src/utils/types.ts index 7d131f5ce..54579c200 100644 --- a/packages/deployer/src/utils/types.ts +++ b/packages/deployer/src/utils/types.ts @@ -75,11 +75,14 @@ export interface UrlDeployerOptions extends BaseDeployerOptions { export type DeployerOptions = UrlDeployerOptions | ProviderDeployerOptions; export interface ContractSources { - [key: string]: string; + [key: string]: { + source: string; + absoluteFilePath: string; + }; } export interface ContractSourceData { - [key: string]: ContractSpecificSourceData; + [contractName: string]: ContractSpecificSourceData; } export interface ContractSpecificSourceData { -- cgit v1.2.3 From 783314c037a85effbc377fdc01cd40235ad388ed Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Mon, 9 Apr 2018 21:54:50 +0200 Subject: Improve on readability --- packages/deployer/src/compiler.ts | 24 ++++++++++++------------ packages/deployer/test/compiler_utils_test.ts | 8 ++------ 2 files changed, 14 insertions(+), 18 deletions(-) (limited to 'packages/deployer') diff --git a/packages/deployer/src/compiler.ts b/packages/deployer/src/compiler.ts index ad35a7794..af0e83dbc 100644 --- a/packages/deployer/src/compiler.ts +++ b/packages/deployer/src/compiler.ts @@ -112,15 +112,16 @@ export class Compiler { await createDirIfDoesNotExistAsync(this._artifactsDir); await createDirIfDoesNotExistAsync(SOLC_BIN_DIR); this._contractSources = await Compiler._getContractSourcesAsync(this._contractsDir); - for (const contractName of _.keys(this._contractSources)) { + const contractNames = _.keys(this._contractSources); + for (const contractName of contractNames) { const contractSource = this._contractSources[contractName]; this._setContractSpecificSourceData(contractSource.source, contractName); } - const contractNames = this._specifiedContracts.has(ALL_CONTRACTS_IDENTIFIER) + const contractNamesToCompile = this._specifiedContracts.has(ALL_CONTRACTS_IDENTIFIER) ? _.keys(this._contractSources) : Array.from(this._specifiedContracts.values()); - for (const contractName of contractNames) { - await this._compileContractAsync(contractName); + for (const contractNameToCompile of contractNamesToCompile) { + await this._compileContractAsync(contractNameToCompile); } } /** @@ -172,8 +173,9 @@ export class Compiler { const solcInstance = solc.setupMethods(requireFromString(solcjs, compilerBinFilename)); logUtils.log(`Compiling ${contractName} with Solidity v${solcVersion}...`); - const source = this._contractSources[contractName].source; - const absoluteFilePath = this._contractSources[contractName].absoluteFilePath; + const contractSource = this._contractSources[contractName]; + const source = contractSource.source; + const absoluteFilePath = contractSource.absoluteFilePath; const standardInput: solc.StandardInput = { language: 'Solidity', sources: { @@ -206,19 +208,17 @@ export class Compiler { if (!_.isUndefined(compiled.errors)) { const SOLIDITY_WARNING = 'warning'; - const isError = (entry: any) => entry.severity !== SOLIDITY_WARNING; - const isWarning = (entry: any) => entry.severity === SOLIDITY_WARNING; - const errors = _.filter(compiled.errors, isError); - const warnings = _.filter(compiled.errors, isWarning); + const errors = _.filter(compiled.errors, entry => entry.severity !== SOLIDITY_WARNING); + const warnings = _.filter(compiled.errors, entry => entry.severity === SOLIDITY_WARNING); if (!_.isEmpty(errors)) { errors.forEach(error => { - const normalizedErrMsg = getNormalizedErrMsg(error.formattedMessage); + const normalizedErrMsg = getNormalizedErrMsg(error.formattedMessage || error.message); logUtils.log(chalk.red(normalizedErrMsg)); }); process.exit(1); } else { warnings.forEach(warning => { - const normalizedWarningMsg = getNormalizedErrMsg(warning.formattedMessage); + const normalizedWarningMsg = getNormalizedErrMsg(warning.formattedMessage || warning.message); logUtils.log(chalk.yellow(normalizedWarningMsg)); }); } diff --git a/packages/deployer/test/compiler_utils_test.ts b/packages/deployer/test/compiler_utils_test.ts index 246304858..8baa30481 100644 --- a/packages/deployer/test/compiler_utils_test.ts +++ b/packages/deployer/test/compiler_utils_test.ts @@ -50,11 +50,7 @@ describe('Compiler utils', () => { const exchangeSource = await fsWrapper.readFileAsync(`${__dirname}/fixtures/contracts/Exchange.sol`, { encoding: 'utf8', }); - expect(parseDependencies(exchangeSource)).to.be.deep.equal([ - 'TokenTransferProxy.sol', - 'Token.sol', - 'SafeMath.sol', - ]); + expect(parseDependencies(exchangeSource)).to.be.deep.equal(['TokenTransferProxy', 'Token', 'SafeMath']); }); it('correctly parses TokenTransferProxy dependencies', async () => { const exchangeSource = await fsWrapper.readFileAsync( @@ -63,7 +59,7 @@ describe('Compiler utils', () => { encoding: 'utf8', }, ); - expect(parseDependencies(exchangeSource)).to.be.deep.equal(['Token.sol', 'Ownable.sol']); + expect(parseDependencies(exchangeSource)).to.be.deep.equal(['Token', 'Ownable']); }); // 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 () => { -- cgit v1.2.3 From eb89926cee2c50ef657b3c033b5637f527d73c6a Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Mon, 9 Apr 2018 22:23:25 +0200 Subject: Implement the resolver --- packages/deployer/package.json | 4 +- packages/deployer/src/compiler.ts | 154 +++++++-------------- packages/deployer/src/utils/compiler.ts | 32 ++--- packages/deployer/src/utils/types.ts | 9 -- packages/deployer/test/compiler_utils_test.ts | 6 +- .../deployer/test/fixtures/contracts/Exchange.sol | 5 +- .../test/fixtures/contracts/TokenTransferProxy.sol | 6 +- .../test/fixtures/contracts/base/Ownable.sol | 27 ---- .../test/fixtures/contracts/base/SafeMath.sol | 2 +- .../test/fixtures/contracts/base/Token.sol | 2 +- packages/deployer/test/fixtures/exchange_bin.ts | 2 +- 11 files changed, 76 insertions(+), 173 deletions(-) delete mode 100644 packages/deployer/test/fixtures/contracts/base/Ownable.sol (limited to 'packages/deployer') diff --git a/packages/deployer/package.json b/packages/deployer/package.json index 3c71cd5ff..d9f2a4a4f 100644 --- a/packages/deployer/package.json +++ b/packages/deployer/package.json @@ -64,9 +64,11 @@ "typedoc": "0xProject/typedoc", "types-bn": "^0.0.1", "typescript": "2.7.1", - "web3-typescript-typings": "^0.10.2" + "web3-typescript-typings": "^0.10.2", + "zeppelin-solidity": "1.8.0" }, "dependencies": { + "@0xproject/resolver": "^0.0.1", "@0xproject/json-schemas": "^0.7.20", "@0xproject/types": "^0.6.0", "@0xproject/typescript-typings": "^0.1.0", diff --git a/packages/deployer/src/compiler.ts b/packages/deployer/src/compiler.ts index af0e83dbc..7a9d62491 100644 --- a/packages/deployer/src/compiler.ts +++ b/packages/deployer/src/compiler.ts @@ -1,3 +1,14 @@ +import { + ContractSource, + ContractSources, + EnumerableResolver, + FallthroughResolver, + FSResolver, + NameResolver, + NPMResolver, + Resolver, + URLResolver, +} from '@0xproject/resolver'; import { ContractAbi } from '@0xproject/types'; import { logUtils, promisify } from '@0xproject/utils'; import chalk from 'chalk'; @@ -13,7 +24,6 @@ import solc = require('solc'); import { binPaths } from './solc/bin_paths'; import { createDirIfDoesNotExistAsync, - findImportIfExist, getContractArtifactIfExistsAsync, getNormalizedErrMsg, parseDependencies, @@ -27,7 +37,6 @@ import { ContractNetworkData, ContractNetworks, ContractSourceData, - ContractSources, ContractSpecificSourceData, } from './utils/types'; import { utils } from './utils/utils'; @@ -40,59 +49,13 @@ const SOLC_BIN_DIR = path.join(__dirname, '..', '..', 'solc_bin'); * to artifact files. */ export class Compiler { + private _resolver: Resolver; + private _nameResolver: NameResolver; private _contractsDir: string; 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 = new Set(); - private _contractSourceData: ContractSourceData = {}; - /** - * Recursively retrieves Solidity source code from directory. - * @param dirPath Directory to search. - * @return Mapping of contract fileName to contract source. - */ - private static async _getContractSourcesAsync(dirPath: string): Promise { - let dirContents: string[] = []; - try { - dirContents = await fsWrapper.readdirAsync(dirPath); - } catch (err) { - throw new Error(`No directory found at ${dirPath}`); - } - let sources: ContractSources = {}; - for (const fileName of dirContents) { - const contentPath = `${dirPath}/${fileName}`; - const contractName = path.basename(fileName, constants.SOLIDITY_FILE_EXTENSION); - const absoluteFilePath = path.resolve(contentPath); - if (path.extname(fileName) === constants.SOLIDITY_FILE_EXTENSION) { - try { - const opts = { - encoding: 'utf8', - }; - const source = await fsWrapper.readFileAsync(contentPath, opts); - sources[contractName] = { - source, - absoluteFilePath, - }; - logUtils.log(`Reading ${contractName} source...`); - } catch (err) { - logUtils.log(`Could not find file at ${contentPath}`); - } - } else { - try { - const nestedSources = await Compiler._getContractSourcesAsync(contentPath); - sources = { - ...sources, - ...nestedSources, - }; - } catch (err) { - logUtils.log(`${contentPath} is not a directory or ${constants.SOLIDITY_FILE_EXTENSION} file`); - } - } - } - return sources; - } /** * Instantiates a new instance of the Compiler class. * @param opts Options specifying directories, network, and optimization settings. @@ -104,6 +67,13 @@ export class Compiler { this._optimizerEnabled = opts.optimizerEnabled; this._artifactsDir = opts.artifactsDir; this._specifiedContracts = opts.specifiedContracts; + this._nameResolver = new NameResolver(path.resolve(this._contractsDir)); + const resolver = new FallthroughResolver(); + resolver.appendResolver(new URLResolver()); + resolver.appendResolver(new NPMResolver(path.resolve(''))); + resolver.appendResolver(new FSResolver()); + resolver.appendResolver(this._nameResolver); + this._resolver = resolver; } /** * Compiles selected Solidity files found in `contractsDir` and writes JSON artifacts to `artifactsDir`. @@ -111,15 +81,15 @@ export class Compiler { public async compileAsync(): Promise { await createDirIfDoesNotExistAsync(this._artifactsDir); await createDirIfDoesNotExistAsync(SOLC_BIN_DIR); - this._contractSources = await Compiler._getContractSourcesAsync(this._contractsDir); - const contractNames = _.keys(this._contractSources); - for (const contractName of contractNames) { - const contractSource = this._contractSources[contractName]; - this._setContractSpecificSourceData(contractSource.source, contractName); + let contractNamesToCompile: string[] = []; + if (this._specifiedContracts.has(ALL_CONTRACTS_IDENTIFIER)) { + const allContracts = this._nameResolver.getAllContracts(); + contractNamesToCompile = _.map(allContracts, contractSource => + path.basename(contractSource.path, constants.SOLIDITY_FILE_EXTENSION), + ); + } else { + contractNamesToCompile = Array.from(this._specifiedContracts.values()); } - const contractNamesToCompile = this._specifiedContracts.has(ALL_CONTRACTS_IDENTIFIER) - ? _.keys(this._contractSources) - : Array.from(this._specifiedContracts.values()); for (const contractNameToCompile of contractNamesToCompile) { await this._compileContractAsync(contractNameToCompile); } @@ -129,13 +99,9 @@ export class Compiler { * @param fileName Name of contract with '.sol' extension. */ private async _compileContractAsync(contractName: string): Promise { - if (_.isUndefined(this._contractSources)) { - throw new Error('Contract sources not yet initialized'); - } - const contractSpecificSourceData = this._contractSourceData[contractName]; + const contractSource = this._resolver.resolve(contractName); const currentArtifactIfExists = await getContractArtifactIfExistsAsync(this._artifactsDir, contractName); - const sourceHash = `0x${contractSpecificSourceData.sourceHash.toString('hex')}`; - const sourceTreeHash = `0x${contractSpecificSourceData.sourceTreeHash.toString('hex')}`; + const sourceTreeHash = `0x${this._getSourceTreeHash(contractSource.path).toString('hex')}`; let shouldCompile = false; if (_.isUndefined(currentArtifactIfExists)) { @@ -149,11 +115,9 @@ export class Compiler { if (!shouldCompile) { return; } + const solcVersionRange = parseSolidityVersionRange(contractSource.source); const availableCompilerVersions = _.keys(binPaths); - const solcVersion = semver.maxSatisfying( - availableCompilerVersions, - contractSpecificSourceData.solcVersionRange, - ); + const solcVersion = semver.maxSatisfying(availableCompilerVersions, solcVersionRange); const fullSolcVersion = binPaths[solcVersion]; const compilerBinFilename = path.join(SOLC_BIN_DIR, fullSolcVersion); let solcjs: string; @@ -173,9 +137,11 @@ export class Compiler { const solcInstance = solc.setupMethods(requireFromString(solcjs, compilerBinFilename)); logUtils.log(`Compiling ${contractName} with Solidity v${solcVersion}...`); - const contractSource = this._contractSources[contractName]; + if (_.isUndefined(contractSource)) { + throw new Error(`Failed to resolve ${contractName}`); + } const source = contractSource.source; - const absoluteFilePath = contractSource.absoluteFilePath; + const absoluteFilePath = contractSource.path; const standardInput: solc.StandardInput = { language: 'Solidity', sources: { @@ -201,9 +167,10 @@ export class Compiler { }, }; const compiled: solc.StandardOutput = JSON.parse( - solcInstance.compileStandardWrapper(JSON.stringify(standardInput), importPath => - findImportIfExist(this._contractSources, importPath), - ), + solcInstance.compileStandardWrapper(JSON.stringify(standardInput), importPath => { + const sourceCodeIfExists = this._resolver.resolve(importPath); + return { contents: sourceCodeIfExists.source }; + }), ); if (!_.isUndefined(compiled.errors)) { @@ -234,11 +201,14 @@ export class Compiler { const runtimeBytecode = `0x${compiledData.evm.deployedBytecode.object}`; const sourceMap = compiledData.evm.bytecode.sourceMap; const sourceMapRuntime = compiledData.evm.deployedBytecode.sourceMap; - const sources = _.keys(compiled.sources); + const unresolvedSourcePaths = _.keys(compiled.sources); + const sources = _.map( + unresolvedSourcePaths, + unresolvedSourcePath => this._resolver.resolve(unresolvedSourcePath).path, + ); const updated_at = Date.now(); const contractNetworkData: ContractNetworkData = { solc_version: solcVersion, - keccak256: sourceHash, source_tree_hash: sourceTreeHash, optimizer_enabled: this._optimizerEnabled, abi, @@ -274,40 +244,20 @@ export class Compiler { await fsWrapper.writeFileAsync(currentArtifactPath, artifactString); logUtils.log(`${contractName} artifact saved!`); } - /** - * Gets contract dependendencies and keccak256 hash from source. - * @param source Source code of contract. - * @return Object with contract dependencies and keccak256 hash of source. - */ - private _setContractSpecificSourceData(source: string, contractName: string): void { - if (!_.isUndefined(this._contractSourceData[contractName])) { - return; - } - const sourceHash = ethUtil.sha3(source); - const solcVersionRange = parseSolidityVersionRange(source); - const dependencies = parseDependencies(source); - const sourceTreeHash = this._getSourceTreeHash(sourceHash, dependencies); - this._contractSourceData[contractName] = { - dependencies, - solcVersionRange, - sourceHash, - sourceTreeHash, - }; - } /** * Gets the source tree hash for a file and its dependencies. * @param fileName Name of contract file. */ - private _getSourceTreeHash(sourceHash: Buffer, dependencies: string[]): Buffer { + private _getSourceTreeHash(importPath: string): Buffer { + const contractSource = this._resolver.resolve(importPath); + const dependencies = parseDependencies(contractSource); + const sourceHash = ethUtil.sha3(contractSource.source); if (dependencies.length === 0) { return sourceHash; } else { - const dependencySourceTreeHashes = _.map(dependencies, dependency => { - const source = this._contractSources[dependency].source; - this._setContractSpecificSourceData(source, dependency); - const sourceData = this._contractSourceData[dependency]; - return this._getSourceTreeHash(sourceData.sourceHash, sourceData.dependencies); - }); + const dependencySourceTreeHashes = _.map(dependencies, (dependency: string) => + this._getSourceTreeHash(dependency), + ); const sourceTreeHashesBuffer = Buffer.concat([sourceHash, ...dependencySourceTreeHashes]); const sourceTreeHash = ethUtil.sha3(sourceTreeHashesBuffer); return sourceTreeHash; diff --git a/packages/deployer/src/utils/compiler.ts b/packages/deployer/src/utils/compiler.ts index b83be221a..79dce5d73 100644 --- a/packages/deployer/src/utils/compiler.ts +++ b/packages/deployer/src/utils/compiler.ts @@ -1,3 +1,4 @@ +import { ContractSource, ContractSources } from '@0xproject/resolver'; import { logUtils } from '@0xproject/utils'; import * as _ from 'lodash'; import * as path from 'path'; @@ -5,7 +6,7 @@ import * as solc from 'solc'; import { constants } from './constants'; import { fsWrapper } from './fs_wrapper'; -import { ContractArtifact, ContractSources } from './types'; +import { ContractArtifact } from './types'; /** * Gets contract data on network or returns if an artifact does not exist. @@ -83,8 +84,9 @@ export function getNormalizedErrMsg(errMsg: string): string { * @param source Contract source code * @return List of dependendencies */ -export function parseDependencies(source: string): string[] { +export function parseDependencies(contractSource: ContractSource): string[] { // TODO: Use a proper parser + const source = contractSource.source; const IMPORT_REGEX = /(import\s)/; const DEPENDENCY_PATH_REGEX = /"([^"]+)"/; // Source: https://github.com/BlockChainCompany/soljitsu/blob/master/lib/shared.js const dependencies: string[] = []; @@ -93,29 +95,13 @@ export function parseDependencies(source: string): string[] { if (!_.isNull(line.match(IMPORT_REGEX))) { const dependencyMatch = line.match(DEPENDENCY_PATH_REGEX); if (!_.isNull(dependencyMatch)) { - const dependencyPath = dependencyMatch[1]; - const contractName = path.basename(dependencyPath, constants.SOLIDITY_FILE_EXTENSION); - dependencies.push(contractName); + let dependencyPath = dependencyMatch[1]; + if (dependencyPath.startsWith('.')) { + dependencyPath = path.join(path.dirname(contractSource.path), dependencyPath); + } + dependencies.push(dependencyPath); } } }); return dependencies; } - -/** - * Callback to resolve dependencies with `solc.compile`. - * @param contractSources Source codes of contracts. - * @param importPath Path to an imported dependency. - * @return Import contents object containing source code of dependency. - */ -export function findImportIfExist(contractSources: ContractSources, importPath: string): solc.ImportContents { - const contractName = path.basename(importPath, constants.SOLIDITY_FILE_EXTENSION); - const source = contractSources[contractName].source; - if (_.isUndefined(source)) { - throw new Error(`Contract source not found for ${contractName}`); - } - const importContents: solc.ImportContents = { - contents: source, - }; - return importContents; -} diff --git a/packages/deployer/src/utils/types.ts b/packages/deployer/src/utils/types.ts index 54579c200..a20d0f627 100644 --- a/packages/deployer/src/utils/types.ts +++ b/packages/deployer/src/utils/types.ts @@ -21,7 +21,6 @@ export interface ContractNetworks { export interface ContractNetworkData { solc_version: string; optimizer_enabled: boolean; - keccak256: string; source_tree_hash: string; abi: ContractAbi; bytecode: string; @@ -74,19 +73,11 @@ export interface UrlDeployerOptions extends BaseDeployerOptions { export type DeployerOptions = UrlDeployerOptions | ProviderDeployerOptions; -export interface ContractSources { - [key: string]: { - source: string; - absoluteFilePath: string; - }; -} - export interface ContractSourceData { [contractName: string]: ContractSpecificSourceData; } export interface ContractSpecificSourceData { - dependencies: string[]; solcVersionRange: string; sourceHash: Buffer; sourceTreeHash: Buffer; diff --git a/packages/deployer/test/compiler_utils_test.ts b/packages/deployer/test/compiler_utils_test.ts index 8baa30481..36e7b321c 100644 --- a/packages/deployer/test/compiler_utils_test.ts +++ b/packages/deployer/test/compiler_utils_test.ts @@ -50,7 +50,7 @@ describe('Compiler utils', () => { const exchangeSource = await fsWrapper.readFileAsync(`${__dirname}/fixtures/contracts/Exchange.sol`, { encoding: 'utf8', }); - expect(parseDependencies(exchangeSource)).to.be.deep.equal(['TokenTransferProxy', 'Token', 'SafeMath']); + // expect(parseDependencies(exchangeSource)).to.be.deep.equal(['ERC20', 'TokenTransferProxy', 'SafeMath']); }); it('correctly parses TokenTransferProxy dependencies', async () => { const exchangeSource = await fsWrapper.readFileAsync( @@ -59,12 +59,12 @@ describe('Compiler utils', () => { encoding: 'utf8', }, ); - expect(parseDependencies(exchangeSource)).to.be.deep.equal(['Token', 'Ownable']); + // expect(parseDependencies(exchangeSource)).to.be.deep.equal(['Ownable', 'ERC20']); }); // 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([]); + // expect(parseDependencies(contractWithCommentedOutDependencies)).to.be.deep.equal([]); }); }); }); diff --git a/packages/deployer/test/fixtures/contracts/Exchange.sol b/packages/deployer/test/fixtures/contracts/Exchange.sol index 1b6819700..1249d21ed 100644 --- a/packages/deployer/test/fixtures/contracts/Exchange.sol +++ b/packages/deployer/test/fixtures/contracts/Exchange.sol @@ -16,10 +16,11 @@ */ -pragma solidity 0.4.14; +pragma solidity ^0.4.14; + +import {ERC20 as Token} from "zeppelin-solidity/contracts/token/ERC20/ERC20.sol"; import "./TokenTransferProxy.sol"; -import "./base/Token.sol"; import "./base/SafeMath.sol"; /// @title Exchange - Facilitates exchange of ERC20 tokens. diff --git a/packages/deployer/test/fixtures/contracts/TokenTransferProxy.sol b/packages/deployer/test/fixtures/contracts/TokenTransferProxy.sol index 90c8e7d66..1ba8a96de 100644 --- a/packages/deployer/test/fixtures/contracts/TokenTransferProxy.sol +++ b/packages/deployer/test/fixtures/contracts/TokenTransferProxy.sol @@ -16,10 +16,10 @@ */ -pragma solidity 0.4.14; +pragma solidity ^0.4.14; -import "./base/Token.sol"; -import "./base/Ownable.sol"; +import { Ownable } from "zeppelin-solidity/contracts/ownership/Ownable.sol"; +import { ERC20 as Token } from "zeppelin-solidity/contracts/token/ERC20/ERC20.sol"; /// @title TokenTransferProxy - Transfers tokens on behalf of contracts that have been approved via decentralized governance. /// @author Amir Bandeali - , Will Warren - diff --git a/packages/deployer/test/fixtures/contracts/base/Ownable.sol b/packages/deployer/test/fixtures/contracts/base/Ownable.sol deleted file mode 100644 index 2a74c3717..000000000 --- a/packages/deployer/test/fixtures/contracts/base/Ownable.sol +++ /dev/null @@ -1,27 +0,0 @@ -pragma solidity 0.4.14; - -/* - * Ownable - * - * Base contract with an owner. - * Provides onlyOwner modifier, which prevents function from running if it is called by anyone other than the owner. - */ - -contract Ownable { - address public owner; - - function Ownable() { - owner = msg.sender; - } - - modifier onlyOwner() { - require(msg.sender == owner); - _; - } - - function transferOwnership(address newOwner) onlyOwner { - if (newOwner != address(0)) { - owner = newOwner; - } - } -} diff --git a/packages/deployer/test/fixtures/contracts/base/SafeMath.sol b/packages/deployer/test/fixtures/contracts/base/SafeMath.sol index 7414684a8..92ce11cde 100644 --- a/packages/deployer/test/fixtures/contracts/base/SafeMath.sol +++ b/packages/deployer/test/fixtures/contracts/base/SafeMath.sol @@ -1,4 +1,4 @@ -pragma solidity 0.4.14; +pragma solidity ^0.4.14; contract SafeMath { function safeMul(uint a, uint b) internal constant returns (uint256) { diff --git a/packages/deployer/test/fixtures/contracts/base/Token.sol b/packages/deployer/test/fixtures/contracts/base/Token.sol index c03f8c567..483010d7d 100644 --- a/packages/deployer/test/fixtures/contracts/base/Token.sol +++ b/packages/deployer/test/fixtures/contracts/base/Token.sol @@ -1,4 +1,4 @@ -pragma solidity 0.4.14; +pragma solidity ^0.4.14; contract Token { diff --git a/packages/deployer/test/fixtures/exchange_bin.ts b/packages/deployer/test/fixtures/exchange_bin.ts index a6eae515e..1bf1f3b38 100644 --- a/packages/deployer/test/fixtures/exchange_bin.ts +++ b/packages/deployer/test/fixtures/exchange_bin.ts @@ -1,4 +1,4 @@ export const constructor_args = '0x000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f4980000000000000000000000008da0d80f5007ef1e431dd2127178d224e32c2ef4'; export const exchange_binary = - '0x6060604052341561000f57600080fd5b604051604080612c4d833981016040528080519060200190919080519060200190919050505b816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505b50505b612b84806100c96000396000f300606060405236156100fa576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806314df96ee146100ff578063288cdc911461014c5780632ac1262214610187578063363349be146101c2578063394c21e7146103bc5780633b30ba591461044b5780634f150787146104a0578063741bcc93146106b25780637e9abb50146107535780638163681e1461078e57806398024a8b14610812578063add1cbc51461085b578063b7b2c7d6146108b0578063baa0181d14610acd578063bc61394a14610c1f578063cfc4d0ec14610cdf578063f06bbf7514610d6d578063ffa1ad7414610d9e575b600080fd5b341561010a57600080fd5b6101326004808035906020019091908035906020019091908035906020019091905050610e2d565b604051808215151515815260200191505060405180910390f35b341561015757600080fd5b610171600480803560001916906020019091905050610e7c565b6040518082815260200191505060405180910390f35b341561019257600080fd5b6101ac600480803560001916906020019091905050610e94565b6040518082815260200191505060405180910390f35b34156101cd57600080fd5b6103a660048080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b8282101561024857848483905060a002016005806020026040519081016040528092919082600560200280828437820191505050505081526020019060010190610203565b5050505050919080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b828210156102c457848483905060c00201600680602002604051908101604052809291908260066020028082843782019150505050508152602001906001019061027f565b5050505050919080359060200190919080351515906020019091908035906020019082018035906020019080806020026020016040519081016040528093929190818152602001838360200280828437820191505050505050919080359060200190820180359060200190808060200260200160405190810160405280939291908181526020018383602002808284378201915050505050509190803590602001908201803590602001908080602002602001604051908101604052809392919081815260200183836020028082843782019150505050505091905050610eac565b6040518082815260200191505060405180910390f35b34156103c757600080fd5b6104356004808060a001906005806020026040519081016040528092919082600560200280828437820191505050505091908060c001906006806020026040519081016040528092919082600660200280828437820191505050505091908035906020019091905050611013565b6040518082815260200191505060405180910390f35b341561045657600080fd5b61045e6114fb565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34156104ab57600080fd5b6106b060048080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b8282101561052657848483905060a0020160058060200260405190810160405280929190826005602002808284378201915050505050815260200190600101906104e1565b5050505050919080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b828210156105a257848483905060c00201600680602002604051908101604052809291908260066020028082843782019150505050508152602001906001019061055d565b50505050509190803590602001908201803590602001908080602002602001604051908101604052809392919081815260200183836020028082843782019150505050505091908035906020019082018035906020019080806020026020016040519081016040528093929190818152602001838360200280828437820191505050505050919080359060200190820180359060200190808060200260200160405190810160405280939291908181526020018383602002808284378201915050505050509190803590602001908201803590602001908080602002602001604051908101604052809392919081815260200183836020028082843782019150505050505091905050611520565b005b34156106bd57600080fd5b6107516004808060a001906005806020026040519081016040528092919082600560200280828437820191505050505091908060c00190600680602002604051908101604052809291908260066020028082843782019150505050509190803590602001909190803560ff1690602001909190803560001916906020019091908035600019169060200190919050506115df565b005b341561075e57600080fd5b610778600480803560001916906020019091905050611605565b6040518082815260200191505060405180910390f35b341561079957600080fd5b6107f8600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919080356000191690602001909190803560ff16906020019091908035600019169060200190919080356000191690602001909190505061164f565b604051808215151515815260200191505060405180910390f35b341561081d57600080fd5b6108456004808035906020019091908035906020019091908035906020019091905050611757565b6040518082815260200191505060405180910390f35b341561086657600080fd5b61086e611776565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34156108bb57600080fd5b610acb60048080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b8282101561093657848483905060a0020160058060200260405190810160405280929190826005602002808284378201915050505050815260200190600101906108f1565b5050505050919080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b828210156109b257848483905060c00201600680602002604051908101604052809291908260066020028082843782019150505050508152602001906001019061096d565b50505050509190803590602001908201803590602001908080602002602001604051908101604052809392919081815260200183836020028082843782019150505050505091908035151590602001909190803590602001908201803590602001908080602002602001604051908101604052809392919081815260200183836020028082843782019150505050505091908035906020019082018035906020019080806020026020016040519081016040528093929190818152602001838360200280828437820191505050505050919080359060200190820180359060200190808060200260200160405190810160405280939291908181526020018383602002808284378201915050505050509190505061179c565b005b3415610ad857600080fd5b610c1d60048080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b82821015610b5357848483905060a002016005806020026040519081016040528092919082600560200280828437820191505050505081526020019060010190610b0e565b5050505050919080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b82821015610bcf57848483905060c002016006806020026040519081016040528092919082600660200280828437820191505050505081526020019060010190610b8a565b5050505050919080359060200190820180359060200190808060200260200160405190810160405280939291908181526020018383602002808284378201915050505050509190505061185e565b005b3415610c2a57600080fd5b610cc96004808060a001906005806020026040519081016040528092919082600560200280828437820191505050505091908060c001906006806020026040519081016040528092919082600660200280828437820191505050505091908035906020019091908035151590602001909190803560ff1690602001909190803560001916906020019091908035600019169060200190919050506118d3565b6040518082815260200191505060405180910390f35b3415610cea57600080fd5b610d4f6004808060a001906005806020026040519081016040528092919082600560200280828437820191505050505091908060c001906006806020026040519081016040528092919082600660200280828437820191505050505091905050612073565b60405180826000191660001916815260200191505060405180910390f35b3415610d7857600080fd5b610d8061231f565b604051808261ffff1661ffff16815260200191505060405180910390f35b3415610da957600080fd5b610db1612325565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015610df25780820151818401525b602081019050610dd6565b50505050905090810190601f168015610e1f5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b60008060008486850991506000821415610e4a5760009250610e73565b610e69610e5a83620f424061235e565b610e64888761235e565b612392565b90506103e8811192505b50509392505050565b60026020528060005260406000206000915090505481565b60036020528060005260406000206000915090505481565b6000806000809150600090505b895181101561100257896000815181101515610ed157fe5b906020019060200201516003600581101515610ee957fe5b602002015173ffffffffffffffffffffffffffffffffffffffff168a82815181101515610f1257fe5b906020019060200201516003600581101515610f2a57fe5b602002015173ffffffffffffffffffffffffffffffffffffffff16141515610f5157600080fd5b610fe582610fe08c84815181101515610f6657fe5b906020019060200201518c85815181101515610f7e57fe5b90602001906020020151610f928d886123ae565b8c8c88815181101515610fa157fe5b906020019060200201518c89815181101515610fb957fe5b906020019060200201518c8a815181101515610fd157fe5b906020019060200201516118d3565b6123c8565b915087821415610ff457611002565b5b8080600101915050610eb9565b8192505b5050979650505050505050565b600061101d612a8c565b6000806101606040519081016040528088600060058110151561103c57fe5b602002015173ffffffffffffffffffffffffffffffffffffffff16815260200188600160058110151561106b57fe5b602002015173ffffffffffffffffffffffffffffffffffffffff16815260200188600260058110151561109a57fe5b602002015173ffffffffffffffffffffffffffffffffffffffff1681526020018860036005811015156110c957fe5b602002015173ffffffffffffffffffffffffffffffffffffffff1681526020018860046005811015156110f857fe5b602002015173ffffffffffffffffffffffffffffffffffffffff16815260200187600060068110151561112757fe5b6020020151815260200187600160068110151561114057fe5b6020020151815260200187600260068110151561115957fe5b6020020151815260200187600360068110151561117257fe5b6020020151815260200187600460068110151561118b57fe5b6020020151815260200161119f8989612073565b6000191681525092503373ffffffffffffffffffffffffffffffffffffffff16836000015173ffffffffffffffffffffffffffffffffffffffff161415156111e657600080fd5b60008360a001511180156111fe575060008360c00151115b801561120a5750600085115b151561121557600080fd5b8261012001514210151561127257826101400151600019166000600381111561123a57fe5b60ff167f36d86c59e00bd73dc19ba3adfe068e4b64ac7e92be35546adeddf1b956a87e9060405160405180910390a3600093506114f1565b61128d8360c00151611288856101400151611605565b6123ae565b915061129985836123e7565b905060008114156112f35782610140015160001916600160038111156112bb57fe5b60ff167f36d86c59e00bd73dc19ba3adfe068e4b64ac7e92be35546adeddf1b956a87e9060405160405180910390a3600093506114f1565b61131d600360008561014001516000191660001916815260200190815260200160002054826123c8565b60036000856101400151600019166000191681526020019081526020016000208190555082604001518360600151604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c0100000000000000000000000002815260140192505050604051809103902060001916836080015173ffffffffffffffffffffffffffffffffffffffff16846000015173ffffffffffffffffffffffffffffffffffffffff167f67d66f160bc93d925d05dae1794c90d2d6d6688b29b84ff069398a9b0458713186604001518760600151611455878a60c001518b60a00151611757565b878a6101400151604051808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200184815260200183815260200182600019166000191681526020019550505050505060405180910390a48093505b5050509392505050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008090505b86518110156115d5576115c7878281518110151561154057fe5b90602001906020020151878381518110151561155857fe5b90602001906020020151878481518110151561157057fe5b90602001906020020151878581518110151561158857fe5b9060200190602002015187868151811015156115a057fe5b9060200190602002015187878151811015156115b857fe5b906020019060200201516115df565b5b8080600101915050611526565b5b50505050505050565b836115f087878760008888886118d3565b1415156115fc57600080fd5b5b505050505050565b600061164760026000846000191660001916815260200190815260200160002054600360008560001916600019168152602001908152602001600020546123c8565b90505b919050565b600060018560405180807f19457468657265756d205369676e6564204d6573736167653a0a333200000000815250601c0182600019166000191681526020019150506040518091039020858585604051600081526020016040526000604051602001526040518085600019166000191681526020018460ff1660ff16815260200183600019166000191681526020018260001916600019168152602001945050505050602060405160208103908084039060008661646e5a03f1151561171457600080fd5b50506020604051035173ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff161490505b95945050505050565b600061176c611766858461235e565b84612392565b90505b9392505050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008090505b87518110156118535761184488828151811015156117bc57fe5b9060200190602002015188838151811015156117d457fe5b9060200190602002015188848151811015156117ec57fe5b9060200190602002015188888681518110151561180557fe5b90602001906020020151888781518110151561181d57fe5b90602001906020020151888881518110151561183557fe5b906020019060200201516118d3565b505b80806001019150506117a2565b5b5050505050505050565b60008090505b83518110156118cc576118bd848281518110151561187e57fe5b90602001906020020151848381518110151561189657fe5b9060200190602002015184848151811015156118ae57fe5b90602001906020020151611013565b505b8080600101915050611864565b5b50505050565b60006118dd612a8c565b600080600080610160604051908101604052808e60006005811015156118ff57fe5b602002015173ffffffffffffffffffffffffffffffffffffffff1681526020018e600160058110151561192e57fe5b602002015173ffffffffffffffffffffffffffffffffffffffff1681526020018e600260058110151561195d57fe5b602002015173ffffffffffffffffffffffffffffffffffffffff1681526020018e600360058110151561198c57fe5b602002015173ffffffffffffffffffffffffffffffffffffffff1681526020018e60046005811015156119bb57fe5b602002015173ffffffffffffffffffffffffffffffffffffffff1681526020018d60006006811015156119ea57fe5b602002015181526020018d6001600681101515611a0357fe5b602002015181526020018d6002600681101515611a1c57fe5b602002015181526020018d6003600681101515611a3557fe5b602002015181526020018d6004600681101515611a4e57fe5b60200201518152602001611a628f8f612073565b600019168152509450600073ffffffffffffffffffffffffffffffffffffffff16856020015173ffffffffffffffffffffffffffffffffffffffff161480611ad957503373ffffffffffffffffffffffffffffffffffffffff16856020015173ffffffffffffffffffffffffffffffffffffffff16145b1515611ae457600080fd5b60008560a00151118015611afc575060008560c00151115b8015611b08575060008b115b1515611b1357600080fd5b611b2985600001518661014001518b8b8b61164f565b1515611b3457600080fd5b84610120015142101515611b91578461014001516000191660006003811115611b5957fe5b60ff167f36d86c59e00bd73dc19ba3adfe068e4b64ac7e92be35546adeddf1b956a87e9060405160405180910390a360009550612063565b611bac8560c00151611ba7876101400151611605565b6123ae565b9350611bb88b856123e7565b95506000861415611c12578461014001516000191660016003811115611bda57fe5b60ff167f36d86c59e00bd73dc19ba3adfe068e4b64ac7e92be35546adeddf1b956a87e9060405160405180910390a360009550612063565b611c25868660c001518760a00151610e2d565b15611c79578461014001516000191660026003811115611c4157fe5b60ff167f36d86c59e00bd73dc19ba3adfe068e4b64ac7e92be35546adeddf1b956a87e9060405160405180910390a360009550612063565b89158015611c8e5750611c8c8587612401565b155b15611ce15784610140015160001916600380811115611ca957fe5b60ff167f36d86c59e00bd73dc19ba3adfe068e4b64ac7e92be35546adeddf1b956a87e9060405160405180910390a360009550612063565b611cf4868660c001518760a00151611757565b9250611d20600260008761014001516000191660001916815260200190815260200160002054876123c8565b600260008761014001516000191660001916815260200190815260200160002081905550611d58856040015186600001513386612751565b1515611d6357600080fd5b611d77856060015133876000015189612751565b1515611d8257600080fd5b600073ffffffffffffffffffffffffffffffffffffffff16856080015173ffffffffffffffffffffffffffffffffffffffff16141515611e815760008560e001511115611e1f57611ddc868660c001518760e00151611757565b9150611e136000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff168660000151876080015185612751565b1515611e1e57600080fd5b5b60008561010001511115611e8057611e41868660c00151876101000151611757565b9050611e746000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1633876080015184612751565b1515611e7f57600080fd5b5b5b84604001518560600151604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c0100000000000000000000000002815260140192505050604051809103902060001916856080015173ffffffffffffffffffffffffffffffffffffffff16866000015173ffffffffffffffffffffffffffffffffffffffff167f0d0b9391970d9a25552f37d436d2aae2925e2bfe1b2a923754bada030c498cb33389604001518a60600151898d8a8a8f6101400151604051808973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200186815260200185815260200184815260200183815260200182600019166000191681526020019850505050505050505060405180910390a48595505b5050505050979650505050505050565b60003083600060058110151561208557fe5b602002015184600160058110151561209957fe5b60200201518560026005811015156120ad57fe5b60200201518660036005811015156120c157fe5b60200201518760046005811015156120d557fe5b60200201518760006006811015156120e957fe5b60200201518860016006811015156120fd57fe5b602002015189600260068110151561211157fe5b60200201518a600360068110151561212557fe5b60200201518b600460068110151561213957fe5b60200201518c600560068110151561214d57fe5b6020020151604051808d73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018c73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018781526020018681526020018581526020018481526020018381526020018281526020019c50505050505050505050505050604051809103902090505b92915050565b61138781565b6040805190810160405280600581526020017f312e302e3000000000000000000000000000000000000000000000000000000081525081565b6000808284029050600084148061237f575082848281151561237c57fe5b04145b151561238757fe5b8091505b5092915050565b60008082848115156123a057fe5b0490508091505b5092915050565b60008282111515156123bc57fe5b81830390505b92915050565b60008082840190508381101515156123dc57fe5b8091505b5092915050565b60008183106123f657816123f8565b825b90505b92915050565b60008060008060008060008060003397506124258a8c60c001518d60a00151611757565b9650600073ffffffffffffffffffffffffffffffffffffffff168b6080015173ffffffffffffffffffffffffffffffffffffffff161415156126d2576000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168b6040015173ffffffffffffffffffffffffffffffffffffffff161495506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168b6060015173ffffffffffffffffffffffffffffffffffffffff161494506125208a8c60c001518d60e00151611757565b93506125368a8c60c001518d6101000151611757565b925085612543578361254e565b61254d87856123c8565b5b91508461255b5782612566565b6125658a846123c8565b5b9050816125986000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff168d600001516128ae565b10806125d15750816125cf6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff168d60000151612972565b105b806126055750806126036000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff168a6128ae565b105b806126395750806126376000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff168a612972565b105b156126475760009850612743565b851580156126805750866126638c604001518d600001516128ae565b108061267f57508661267d8c604001518d60000151612972565b105b5b1561268e5760009850612743565b841580156126bf5750896126a68c606001518a6128ae565b10806126be5750896126bc8c606001518a612972565b105b5b156126cd5760009850612743565b61273e565b866126e58c604001518d600001516128ae565b10806127015750866126ff8c604001518d60000151612972565b105b806127185750896127168c606001518a6128ae565b105b8061272f57508961272d8c606001518a612972565b105b1561273d5760009850612743565b5b600198505b505050505050505092915050565b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166315dacbea868686866000604051602001526040518563ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001828152602001945050505050602060405180830381600087803b151561288857600080fd5b6102c65a03f1151561289957600080fd5b5050506040518051905090505b949350505050565b60008273ffffffffffffffffffffffffffffffffffffffff166370a0823161138761ffff16846040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600088803b151561295157600080fd5b87f1151561295e57600080fd5b505050506040518051905090505b92915050565b60008273ffffffffffffffffffffffffffffffffffffffff1663dd62ed3e61138761ffff1684600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff166040518463ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200192505050602060405180830381600088803b1515612a6b57600080fd5b87f11515612a7857600080fd5b505050506040518051905090505b92915050565b61016060405190810160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff16815260200160008152602001600081526020016000815260200160008152602001600081526020016000801916815250905600a165627a7a72305820df5cabdc3a116e993e10bfb14823d18d9b798038d4c463a1703f9a584c456b7e0029'; + '0x6060604052341561000f57600080fd5b604051604080612c2583398101604052808051906020019091908051906020019091905050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505050612b5f806100c66000396000f3006060604052600436106100fc576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806314df96ee14610101578063288cdc911461014e5780632ac1262214610189578063363349be146101c4578063394c21e7146103be5780633b30ba591461044d5780634f150787146104a2578063741bcc93146106b45780637e9abb50146107555780638163681e1461079057806398024a8b14610814578063add1cbc51461085d578063b7b2c7d6146108b2578063baa0181d14610acf578063bc61394a14610c21578063cfc4d0ec14610ce1578063f06bbf7514610d6f578063ffa1ad7414610da0575b600080fd5b341561010c57600080fd5b6101346004808035906020019091908035906020019091908035906020019091905050610e2e565b604051808215151515815260200191505060405180910390f35b341561015957600080fd5b610173600480803560001916906020019091905050610e86565b6040518082815260200191505060405180910390f35b341561019457600080fd5b6101ae600480803560001916906020019091905050610e9e565b6040518082815260200191505060405180910390f35b34156101cf57600080fd5b6103a860048080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b8282101561024a57848483905060a002016005806020026040519081016040528092919082600560200280828437820191505050505081526020019060010190610205565b5050505050919080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b828210156102c657848483905060c002016006806020026040519081016040528092919082600660200280828437820191505050505081526020019060010190610281565b5050505050919080359060200190919080351515906020019091908035906020019082018035906020019080806020026020016040519081016040528093929190818152602001838360200280828437820191505050505050919080359060200190820180359060200190808060200260200160405190810160405280939291908181526020018383602002808284378201915050505050509190803590602001908201803590602001908080602002602001604051908101604052809392919081815260200183836020028082843782019150505050505091905050610eb6565b6040518082815260200191505060405180910390f35b34156103c957600080fd5b6104376004808060a001906005806020026040519081016040528092919082600560200280828437820191505050505091908060c00190600680602002604051908101604052809291908260066020028082843782019150505050509190803590602001909190505061101b565b6040518082815260200191505060405180910390f35b341561045857600080fd5b610460611503565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34156104ad57600080fd5b6106b260048080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b8282101561052857848483905060a0020160058060200260405190810160405280929190826005602002808284378201915050505050815260200190600101906104e3565b5050505050919080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b828210156105a457848483905060c00201600680602002604051908101604052809291908260066020028082843782019150505050508152602001906001019061055f565b50505050509190803590602001908201803590602001908080602002602001604051908101604052809392919081815260200183836020028082843782019150505050505091908035906020019082018035906020019080806020026020016040519081016040528093929190818152602001838360200280828437820191505050505050919080359060200190820180359060200190808060200260200160405190810160405280939291908181526020018383602002808284378201915050505050509190803590602001908201803590602001908080602002602001604051908101604052809392919081815260200183836020028082843782019150505050505091905050611528565b005b34156106bf57600080fd5b6107536004808060a001906005806020026040519081016040528092919082600560200280828437820191505050505091908060c00190600680602002604051908101604052809291908260066020028082843782019150505050509190803590602001909190803560ff1690602001909190803560001916906020019091908035600019169060200190919050506115e5565b005b341561076057600080fd5b61077a60048080356000191690602001909190505061160a565b6040518082815260200191505060405180910390f35b341561079b57600080fd5b6107fa600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919080356000191690602001909190803560ff169060200190919080356000191690602001909190803560001916906020019091905050611653565b604051808215151515815260200191505060405180910390f35b341561081f57600080fd5b610847600480803590602001909190803590602001909190803590602001909190505061174d565b6040518082815260200191505060405180910390f35b341561086857600080fd5b61087061176b565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34156108bd57600080fd5b610acd60048080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b8282101561093857848483905060a0020160058060200260405190810160405280929190826005602002808284378201915050505050815260200190600101906108f3565b5050505050919080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b828210156109b457848483905060c00201600680602002604051908101604052809291908260066020028082843782019150505050508152602001906001019061096f565b505050505091908035906020019082018035906020019080806020026020016040519081016040528093929190818152602001838360200280828437820191505050505050919080351515906020019091908035906020019082018035906020019080806020026020016040519081016040528093929190818152602001838360200280828437820191505050505050919080359060200190820180359060200190808060200260200160405190810160405280939291908181526020018383602002808284378201915050505050509190803590602001908201803590602001908080602002602001604051908101604052809392919081815260200183836020028082843782019150505050505091905050611791565b005b3415610ada57600080fd5b610c1f60048080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b82821015610b5557848483905060a002016005806020026040519081016040528092919082600560200280828437820191505050505081526020019060010190610b10565b5050505050919080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b82821015610bd157848483905060c002016006806020026040519081016040528092919082600660200280828437820191505050505081526020019060010190610b8c565b50505050509190803590602001908201803590602001908080602002602001604051908101604052809392919081815260200183836020028082843782019150505050505091905050611851565b005b3415610c2c57600080fd5b610ccb6004808060a001906005806020026040519081016040528092919082600560200280828437820191505050505091908060c001906006806020026040519081016040528092919082600660200280828437820191505050505091908035906020019091908035151590602001909190803560ff1690602001909190803560001916906020019091908035600019169060200190919050506118c4565b6040518082815260200191505060405180910390f35b3415610cec57600080fd5b610d516004808060a001906005806020026040519081016040528092919082600560200280828437820191505050505091908060c001906006806020026040519081016040528092919082600660200280828437820191505050505091905050612064565b60405180826000191660001916815260200191505060405180910390f35b3415610d7a57600080fd5b610d8261230f565b604051808261ffff1661ffff16815260200191505060405180910390f35b3415610dab57600080fd5b610db3612315565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015610df3578082015181840152602081019050610dd8565b50505050905090810190601f168015610e205780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b600080600084801515610e3d57fe5b86850991506000821415610e545760009250610e7d565b610e73610e6483620f424061234e565b610e6e888761234e565b612381565b90506103e8811192505b50509392505050565b60026020528060005260406000206000915090505481565b60036020528060005260406000206000915090505481565b6000806000809150600090505b895181101561100b57896000815181101515610edb57fe5b906020019060200201516003600581101515610ef357fe5b602002015173ffffffffffffffffffffffffffffffffffffffff168a82815181101515610f1c57fe5b906020019060200201516003600581101515610f3457fe5b602002015173ffffffffffffffffffffffffffffffffffffffff16141515610f5b57600080fd5b610fef82610fea8c84815181101515610f7057fe5b906020019060200201518c85815181101515610f8857fe5b90602001906020020151610f9c8d8861239c565b8c8c88815181101515610fab57fe5b906020019060200201518c89815181101515610fc357fe5b906020019060200201518c8a815181101515610fdb57fe5b906020019060200201516118c4565b6123b5565b915087821415610ffe5761100b565b8080600101915050610ec3565b8192505050979650505050505050565b6000611025612a67565b6000806101606040519081016040528088600060058110151561104457fe5b602002015173ffffffffffffffffffffffffffffffffffffffff16815260200188600160058110151561107357fe5b602002015173ffffffffffffffffffffffffffffffffffffffff1681526020018860026005811015156110a257fe5b602002015173ffffffffffffffffffffffffffffffffffffffff1681526020018860036005811015156110d157fe5b602002015173ffffffffffffffffffffffffffffffffffffffff16815260200188600460058110151561110057fe5b602002015173ffffffffffffffffffffffffffffffffffffffff16815260200187600060068110151561112f57fe5b6020020151815260200187600160068110151561114857fe5b6020020151815260200187600260068110151561116157fe5b6020020151815260200187600360068110151561117a57fe5b6020020151815260200187600460068110151561119357fe5b602002015181526020016111a78989612064565b6000191681525092503373ffffffffffffffffffffffffffffffffffffffff16836000015173ffffffffffffffffffffffffffffffffffffffff161415156111ee57600080fd5b60008360a00151118015611206575060008360c00151115b80156112125750600085115b151561121d57600080fd5b8261012001514210151561127a57826101400151600019166000600381111561124257fe5b60ff167f36d86c59e00bd73dc19ba3adfe068e4b64ac7e92be35546adeddf1b956a87e9060405160405180910390a3600093506114f9565b6112958360c0015161129085610140015161160a565b61239c565b91506112a185836123d3565b905060008114156112fb5782610140015160001916600160038111156112c357fe5b60ff167f36d86c59e00bd73dc19ba3adfe068e4b64ac7e92be35546adeddf1b956a87e9060405160405180910390a3600093506114f9565b611325600360008561014001516000191660001916815260200190815260200160002054826123b5565b60036000856101400151600019166000191681526020019081526020016000208190555082604001518360600151604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c0100000000000000000000000002815260140192505050604051809103902060001916836080015173ffffffffffffffffffffffffffffffffffffffff16846000015173ffffffffffffffffffffffffffffffffffffffff167f67d66f160bc93d925d05dae1794c90d2d6d6688b29b84ff069398a9b045871318660400151876060015161145d878a60c001518b60a0015161174d565b878a6101400151604051808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200184815260200183815260200182600019166000191681526020019550505050505060405180910390a48093505b5050509392505050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008090505b86518110156115dc576115cf878281518110151561154857fe5b90602001906020020151878381518110151561156057fe5b90602001906020020151878481518110151561157857fe5b90602001906020020151878581518110151561159057fe5b9060200190602002015187868151811015156115a857fe5b9060200190602002015187878151811015156115c057fe5b906020019060200201516115e5565b808060010191505061152e565b50505050505050565b836115f687878760008888886118c4565b14151561160257600080fd5b505050505050565b600061164c60026000846000191660001916815260200190815260200160002054600360008560001916600019168152602001908152602001600020546123b5565b9050919050565b600060018560405180807f19457468657265756d205369676e6564204d6573736167653a0a333200000000815250601c0182600019166000191681526020019150506040518091039020858585604051600081526020016040526040518085600019166000191681526020018460ff1660ff1681526020018360001916600019168152602001826000191660001916815260200194505050505060206040516020810390808403906000865af1151561170b57600080fd5b50506020604051035173ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff1614905095945050505050565b600061176261175c858461234e565b84612381565b90509392505050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008090505b87518110156118475761183988828151811015156117b157fe5b9060200190602002015188838151811015156117c957fe5b9060200190602002015188848151811015156117e157fe5b906020019060200201518888868151811015156117fa57fe5b90602001906020020151888781518110151561181257fe5b90602001906020020151888881518110151561182a57fe5b906020019060200201516118c4565b508080600101915050611797565b5050505050505050565b60008090505b83518110156118be576118b0848281518110151561187157fe5b90602001906020020151848381518110151561188957fe5b9060200190602002015184848151811015156118a157fe5b9060200190602002015161101b565b508080600101915050611857565b50505050565b60006118ce612a67565b600080600080610160604051908101604052808e60006005811015156118f057fe5b602002015173ffffffffffffffffffffffffffffffffffffffff1681526020018e600160058110151561191f57fe5b602002015173ffffffffffffffffffffffffffffffffffffffff1681526020018e600260058110151561194e57fe5b602002015173ffffffffffffffffffffffffffffffffffffffff1681526020018e600360058110151561197d57fe5b602002015173ffffffffffffffffffffffffffffffffffffffff1681526020018e60046005811015156119ac57fe5b602002015173ffffffffffffffffffffffffffffffffffffffff1681526020018d60006006811015156119db57fe5b602002015181526020018d60016006811015156119f457fe5b602002015181526020018d6002600681101515611a0d57fe5b602002015181526020018d6003600681101515611a2657fe5b602002015181526020018d6004600681101515611a3f57fe5b60200201518152602001611a538f8f612064565b600019168152509450600073ffffffffffffffffffffffffffffffffffffffff16856020015173ffffffffffffffffffffffffffffffffffffffff161480611aca57503373ffffffffffffffffffffffffffffffffffffffff16856020015173ffffffffffffffffffffffffffffffffffffffff16145b1515611ad557600080fd5b60008560a00151118015611aed575060008560c00151115b8015611af9575060008b115b1515611b0457600080fd5b611b1a85600001518661014001518b8b8b611653565b1515611b2557600080fd5b84610120015142101515611b82578461014001516000191660006003811115611b4a57fe5b60ff167f36d86c59e00bd73dc19ba3adfe068e4b64ac7e92be35546adeddf1b956a87e9060405160405180910390a360009550612054565b611b9d8560c00151611b9887610140015161160a565b61239c565b9350611ba98b856123d3565b95506000861415611c03578461014001516000191660016003811115611bcb57fe5b60ff167f36d86c59e00bd73dc19ba3adfe068e4b64ac7e92be35546adeddf1b956a87e9060405160405180910390a360009550612054565b611c16868660c001518760a00151610e2e565b15611c6a578461014001516000191660026003811115611c3257fe5b60ff167f36d86c59e00bd73dc19ba3adfe068e4b64ac7e92be35546adeddf1b956a87e9060405160405180910390a360009550612054565b89158015611c7f5750611c7d85876123ec565b155b15611cd25784610140015160001916600380811115611c9a57fe5b60ff167f36d86c59e00bd73dc19ba3adfe068e4b64ac7e92be35546adeddf1b956a87e9060405160405180910390a360009550612054565b611ce5868660c001518760a0015161174d565b9250611d11600260008761014001516000191660001916815260200190815260200160002054876123b5565b600260008761014001516000191660001916815260200190815260200160002081905550611d4985604001518660000151338661273c565b1515611d5457600080fd5b611d6885606001513387600001518961273c565b1515611d7357600080fd5b600073ffffffffffffffffffffffffffffffffffffffff16856080015173ffffffffffffffffffffffffffffffffffffffff16141515611e725760008560e001511115611e1057611dcd868660c001518760e0015161174d565b9150611e046000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff16866000015187608001518561273c565b1515611e0f57600080fd5b5b60008561010001511115611e7157611e32868660c0015187610100015161174d565b9050611e656000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff163387608001518461273c565b1515611e7057600080fd5b5b5b84604001518560600151604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c0100000000000000000000000002815260140192505050604051809103902060001916856080015173ffffffffffffffffffffffffffffffffffffffff16866000015173ffffffffffffffffffffffffffffffffffffffff167f0d0b9391970d9a25552f37d436d2aae2925e2bfe1b2a923754bada030c498cb33389604001518a60600151898d8a8a8f6101400151604051808973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200186815260200185815260200184815260200183815260200182600019166000191681526020019850505050505050505060405180910390a48595505b5050505050979650505050505050565b60003083600060058110151561207657fe5b602002015184600160058110151561208a57fe5b602002015185600260058110151561209e57fe5b60200201518660036005811015156120b257fe5b60200201518760046005811015156120c657fe5b60200201518760006006811015156120da57fe5b60200201518860016006811015156120ee57fe5b602002015189600260068110151561210257fe5b60200201518a600360068110151561211657fe5b60200201518b600460068110151561212a57fe5b60200201518c600560068110151561213e57fe5b6020020151604051808d73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018c73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018781526020018681526020018581526020018481526020018381526020018281526020019c505050505050505050505050506040518091039020905092915050565b61138781565b6040805190810160405280600581526020017f312e302e3000000000000000000000000000000000000000000000000000000081525081565b6000808284029050600084148061236f575082848281151561236c57fe5b04145b151561237757fe5b8091505092915050565b600080828481151561238f57fe5b0490508091505092915050565b60008282111515156123aa57fe5b818303905092915050565b60008082840190508381101515156123c957fe5b8091505092915050565b60008183106123e257816123e4565b825b905092915050565b60008060008060008060008060003397506124108a8c60c001518d60a0015161174d565b9650600073ffffffffffffffffffffffffffffffffffffffff168b6080015173ffffffffffffffffffffffffffffffffffffffff161415156126bd576000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168b6040015173ffffffffffffffffffffffffffffffffffffffff161495506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168b6060015173ffffffffffffffffffffffffffffffffffffffff1614945061250b8a8c60c001518d60e0015161174d565b93506125218a8c60c001518d610100015161174d565b92508561252e5783612539565b61253887856123b5565b5b9150846125465782612551565b6125508a846123b5565b5b9050816125836000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff168d6000015161288b565b10806125bc5750816125ba6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff168d6000015161294e565b105b806125f05750806125ee6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff168a61288b565b105b806126245750806126226000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff168a61294e565b105b15612632576000985061272e565b8515801561266b57508661264e8c604001518d6000015161288b565b108061266a5750866126688c604001518d6000015161294e565b105b5b15612679576000985061272e565b841580156126aa5750896126918c606001518a61288b565b10806126a95750896126a78c606001518a61294e565b105b5b156126b8576000985061272e565b612729565b866126d08c604001518d6000015161288b565b10806126ec5750866126ea8c604001518d6000015161294e565b105b806127035750896127018c606001518a61288b565b105b8061271a5750896127188c606001518a61294e565b105b15612728576000985061272e565b5b600198505b505050505050505092915050565b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166315dacbea868686866040518563ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001828152602001945050505050602060405180830381600087803b151561286a57600080fd5b5af1151561287757600080fd5b505050604051805190509050949350505050565b60008273ffffffffffffffffffffffffffffffffffffffff166370a0823161138761ffff16846040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600088803b151561292e57600080fd5b87f1151561293b57600080fd5b5050505060405180519050905092915050565b60008273ffffffffffffffffffffffffffffffffffffffff1663dd62ed3e61138761ffff1684600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff166040518463ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200192505050602060405180830381600088803b1515612a4757600080fd5b87f11515612a5457600080fd5b5050505060405180519050905092915050565b61016060405190810160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff16815260200160008152602001600081526020016000815260200160008152602001600081526020016000801916815250905600a165627a7a72305820df5cabdc3a116e993e10bfb14823d18d9b798038d4c463a1703f9a584c456b7e0029'; -- cgit v1.2.3 From 06b4f007f88b6eb58a9d49997318b872be9f5dea Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Fri, 13 Apr 2018 13:18:59 +0200 Subject: Introduce packagePath --- packages/deployer/src/compiler.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'packages/deployer') diff --git a/packages/deployer/src/compiler.ts b/packages/deployer/src/compiler.ts index 7a9d62491..ef4e048d5 100644 --- a/packages/deployer/src/compiler.ts +++ b/packages/deployer/src/compiler.ts @@ -70,7 +70,8 @@ export class Compiler { this._nameResolver = new NameResolver(path.resolve(this._contractsDir)); const resolver = new FallthroughResolver(); resolver.appendResolver(new URLResolver()); - resolver.appendResolver(new NPMResolver(path.resolve(''))); + const packagePath = path.resolve(''); + resolver.appendResolver(new NPMResolver(packagePath)); resolver.appendResolver(new FSResolver()); resolver.appendResolver(this._nameResolver); this._resolver = resolver; -- cgit v1.2.3 From 74012ad584ba93043e60f143d88619f580ceed08 Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Fri, 13 Apr 2018 13:20:54 +0200 Subject: Rename getAllContracts to getAll --- packages/deployer/src/compiler.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'packages/deployer') diff --git a/packages/deployer/src/compiler.ts b/packages/deployer/src/compiler.ts index ef4e048d5..0a99e5659 100644 --- a/packages/deployer/src/compiler.ts +++ b/packages/deployer/src/compiler.ts @@ -84,7 +84,7 @@ export class Compiler { await createDirIfDoesNotExistAsync(SOLC_BIN_DIR); let contractNamesToCompile: string[] = []; if (this._specifiedContracts.has(ALL_CONTRACTS_IDENTIFIER)) { - const allContracts = this._nameResolver.getAllContracts(); + const allContracts = this._nameResolver.getAll(); contractNamesToCompile = _.map(allContracts, contractSource => path.basename(contractSource.path, constants.SOLIDITY_FILE_EXTENSION), ); -- cgit v1.2.3 From e5cf41b3134d6cd5fdda995aa81ec23e51bb5145 Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Fri, 13 Apr 2018 13:27:52 +0200 Subject: Uncomment tests --- packages/deployer/src/compiler.ts | 9 +++------ packages/deployer/test/compiler_utils_test.ts | 6 +++--- 2 files changed, 6 insertions(+), 9 deletions(-) (limited to 'packages/deployer') diff --git a/packages/deployer/src/compiler.ts b/packages/deployer/src/compiler.ts index 0a99e5659..dfbe469a7 100644 --- a/packages/deployer/src/compiler.ts +++ b/packages/deployer/src/compiler.ts @@ -102,7 +102,7 @@ export class Compiler { private async _compileContractAsync(contractName: string): Promise { const contractSource = this._resolver.resolve(contractName); const currentArtifactIfExists = await getContractArtifactIfExistsAsync(this._artifactsDir, contractName); - const sourceTreeHash = `0x${this._getSourceTreeHash(contractSource.path).toString('hex')}`; + const sourceTreeHashHex = `0x${this._getSourceTreeHash(contractSource.path).toString('hex')}`; let shouldCompile = false; if (_.isUndefined(currentArtifactIfExists)) { @@ -111,7 +111,7 @@ export class Compiler { const currentArtifact = currentArtifactIfExists as ContractArtifact; shouldCompile = currentArtifact.networks[this._networkId].optimizer_enabled !== this._optimizerEnabled || - currentArtifact.networks[this._networkId].source_tree_hash !== sourceTreeHash; + currentArtifact.networks[this._networkId].source_tree_hash !== sourceTreeHashHex; } if (!shouldCompile) { return; @@ -138,9 +138,6 @@ export class Compiler { const solcInstance = solc.setupMethods(requireFromString(solcjs, compilerBinFilename)); logUtils.log(`Compiling ${contractName} with Solidity v${solcVersion}...`); - if (_.isUndefined(contractSource)) { - throw new Error(`Failed to resolve ${contractName}`); - } const source = contractSource.source; const absoluteFilePath = contractSource.path; const standardInput: solc.StandardInput = { @@ -210,7 +207,7 @@ export class Compiler { const updated_at = Date.now(); const contractNetworkData: ContractNetworkData = { solc_version: solcVersion, - source_tree_hash: sourceTreeHash, + source_tree_hash: sourceTreeHashHex, optimizer_enabled: this._optimizerEnabled, abi, bytecode, diff --git a/packages/deployer/test/compiler_utils_test.ts b/packages/deployer/test/compiler_utils_test.ts index 36e7b321c..7e7ae1200 100644 --- a/packages/deployer/test/compiler_utils_test.ts +++ b/packages/deployer/test/compiler_utils_test.ts @@ -50,7 +50,7 @@ describe('Compiler utils', () => { const exchangeSource = await fsWrapper.readFileAsync(`${__dirname}/fixtures/contracts/Exchange.sol`, { encoding: 'utf8', }); - // expect(parseDependencies(exchangeSource)).to.be.deep.equal(['ERC20', 'TokenTransferProxy', 'SafeMath']); + expect(parseDependencies(exchangeSource)).to.be.deep.equal(['ERC20', 'TokenTransferProxy', 'SafeMath']); }); it('correctly parses TokenTransferProxy dependencies', async () => { const exchangeSource = await fsWrapper.readFileAsync( @@ -59,12 +59,12 @@ describe('Compiler utils', () => { encoding: 'utf8', }, ); - // expect(parseDependencies(exchangeSource)).to.be.deep.equal(['Ownable', 'ERC20']); + expect(parseDependencies(exchangeSource)).to.be.deep.equal(['Ownable', 'ERC20']); }); // 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([]); + expect(parseDependencies(contractWithCommentedOutDependencies)).to.be.deep.equal([]); }); }); }); -- cgit v1.2.3 From d8ef76fd5efe63ec8f6205a73494ce388e64391f Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Mon, 16 Apr 2018 16:38:55 +0200 Subject: Rename resolver to sol-resolver --- packages/deployer/package.json | 2 +- packages/deployer/src/compiler.ts | 2 +- packages/deployer/src/utils/compiler.ts | 2 +- packages/deployer/test/compiler_utils_test.ts | 29 ++++++++++++++-------- .../deployer/test/fixtures/contracts/Exchange.sol | 2 +- .../test/fixtures/contracts/TokenTransferProxy.sol | 2 +- 6 files changed, 23 insertions(+), 16 deletions(-) (limited to 'packages/deployer') diff --git a/packages/deployer/package.json b/packages/deployer/package.json index d9f2a4a4f..d529382ac 100644 --- a/packages/deployer/package.json +++ b/packages/deployer/package.json @@ -68,7 +68,7 @@ "zeppelin-solidity": "1.8.0" }, "dependencies": { - "@0xproject/resolver": "^0.0.1", + "@0xproject/sol-resolver": "^0.0.1", "@0xproject/json-schemas": "^0.7.20", "@0xproject/types": "^0.6.0", "@0xproject/typescript-typings": "^0.1.0", diff --git a/packages/deployer/src/compiler.ts b/packages/deployer/src/compiler.ts index dfbe469a7..a3c8004ec 100644 --- a/packages/deployer/src/compiler.ts +++ b/packages/deployer/src/compiler.ts @@ -8,7 +8,7 @@ import { NPMResolver, Resolver, URLResolver, -} from '@0xproject/resolver'; +} from '@0xproject/sol-resolver'; import { ContractAbi } from '@0xproject/types'; import { logUtils, promisify } from '@0xproject/utils'; import chalk from 'chalk'; diff --git a/packages/deployer/src/utils/compiler.ts b/packages/deployer/src/utils/compiler.ts index 79dce5d73..c571b2581 100644 --- a/packages/deployer/src/utils/compiler.ts +++ b/packages/deployer/src/utils/compiler.ts @@ -1,4 +1,4 @@ -import { ContractSource, ContractSources } from '@0xproject/resolver'; +import { ContractSource, ContractSources } from '@0xproject/sol-resolver'; import { logUtils } from '@0xproject/utils'; import * as _ from 'lodash'; import * as path from 'path'; diff --git a/packages/deployer/test/compiler_utils_test.ts b/packages/deployer/test/compiler_utils_test.ts index 7e7ae1200..e2b95f289 100644 --- a/packages/deployer/test/compiler_utils_test.ts +++ b/packages/deployer/test/compiler_utils_test.ts @@ -47,24 +47,31 @@ describe('Compiler utils', () => { }); describe('#parseDependencies', () => { it('correctly parses Exchange dependencies', async () => { - const exchangeSource = await fsWrapper.readFileAsync(`${__dirname}/fixtures/contracts/Exchange.sol`, { + const path = `${__dirname}/fixtures/contracts/Exchange.sol`; + const source = await fsWrapper.readFileAsync(path, { encoding: 'utf8', }); - expect(parseDependencies(exchangeSource)).to.be.deep.equal(['ERC20', 'TokenTransferProxy', 'SafeMath']); + expect(parseDependencies({ source, path })).to.be.deep.equal([ + 'zeppelin-solidity/contracts/token/ERC20/ERC20.sol', + '/home/circleci/repo/packages/deployer/lib/test/fixtures/contracts/TokenTransferProxy.sol', + '/home/circleci/repo/packages/deployer/lib/test/fixtures/contracts/base/SafeMath.sol', + ]); }); it('correctly parses TokenTransferProxy dependencies', async () => { - const exchangeSource = await fsWrapper.readFileAsync( - `${__dirname}/fixtures/contracts/TokenTransferProxy.sol`, - { - encoding: 'utf8', - }, - ); - expect(parseDependencies(exchangeSource)).to.be.deep.equal(['Ownable', 'ERC20']); + const path = `${__dirname}/fixtures/contracts/TokenTransferProxy.sol`; + const source = await fsWrapper.readFileAsync(path, { + encoding: 'utf8', + }); + expect(parseDependencies({ source, path })).to.be.deep.equal([ + 'zeppelin-solidity/contracts/ownership/Ownable.sol', + 'zeppelin-solidity/contracts/token/ERC20/ERC20.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 path = ''; + const source = `// import "./TokenTransferProxy.sol";`; + expect(parseDependencies({ path, source })).to.be.deep.equal([]); }); }); }); diff --git a/packages/deployer/test/fixtures/contracts/Exchange.sol b/packages/deployer/test/fixtures/contracts/Exchange.sol index 1249d21ed..e3725335b 100644 --- a/packages/deployer/test/fixtures/contracts/Exchange.sol +++ b/packages/deployer/test/fixtures/contracts/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. diff --git a/packages/deployer/test/fixtures/contracts/TokenTransferProxy.sol b/packages/deployer/test/fixtures/contracts/TokenTransferProxy.sol index 1ba8a96de..44570d459 100644 --- a/packages/deployer/test/fixtures/contracts/TokenTransferProxy.sol +++ b/packages/deployer/test/fixtures/contracts/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. -- cgit v1.2.3