aboutsummaryrefslogtreecommitdiffstats
path: root/packages
diff options
context:
space:
mode:
Diffstat (limited to 'packages')
-rw-r--r--packages/0x.js/test/artifacts_test.ts4
-rw-r--r--packages/0x.js/test/utils/web3_wrapper.ts5
-rw-r--r--packages/contract-wrappers/test/artifacts_test.ts4
-rw-r--r--packages/contract-wrappers/test/utils/web3_wrapper.ts5
-rw-r--r--packages/contracts/package.json2
-rw-r--r--packages/contracts/src/utils/web3_wrapper.ts13
-rw-r--r--packages/contracts/test/global_hooks.ts4
-rw-r--r--packages/contracts/test/utils/coverage.ts21
-rw-r--r--packages/dev-utils/CHANGELOG.json4
-rw-r--r--packages/dev-utils/package.json1
-rw-r--r--packages/dev-utils/src/coverage.ts21
-rw-r--r--packages/dev-utils/src/index.ts1
-rw-r--r--packages/dev-utils/src/web3_factory.ts20
-rw-r--r--packages/metacoin/test/utils/config.ts4
-rw-r--r--packages/metacoin/test/utils/coverage.ts5
-rw-r--r--packages/metacoin/test/utils/web3_wrapper.ts12
-rw-r--r--packages/migrations/package.json2
-rw-r--r--packages/migrations/src/migrate.ts3
-rw-r--r--packages/order-utils/test/utils/web3_wrapper.ts5
-rw-r--r--packages/order-watcher/test/utils/web3_wrapper.ts5
-rw-r--r--packages/sol-compiler/CHANGELOG.json4
-rw-r--r--packages/sol-compiler/src/compiler.ts13
-rw-r--r--packages/sol-compiler/src/index.ts1
-rw-r--r--packages/sol-compiler/src/utils/types.ts1
-rw-r--r--packages/sol-compiler/test/util/provider.ts3
-rw-r--r--packages/sol-cov/CHANGELOG.json22
-rw-r--r--packages/sol-cov/package.json5
-rw-r--r--packages/sol-cov/src/artifact_adapters/abstract_artifact_adapter.ts5
-rw-r--r--packages/sol-cov/src/artifact_adapters/sol_compiler_artifact_adapter.ts49
-rw-r--r--packages/sol-cov/src/artifact_adapters/truffle_artifact_adapter.ts43
-rw-r--r--packages/sol-cov/src/collect_contract_data.ts31
-rw-r--r--packages/sol-cov/src/constants.ts2
-rw-r--r--packages/sol-cov/src/coverage_manager.ts105
-rw-r--r--packages/sol-cov/src/coverage_subprovider.ts80
-rw-r--r--packages/sol-cov/src/index.ts4
-rw-r--r--packages/sol-cov/src/trace.ts104
-rw-r--r--packages/sol-cov/src/types.ts4
-rw-r--r--packages/sol-cov/test/sol_compiler_artifact_adapter_test.ts (renamed from packages/sol-cov/test/collect_contracts_data_test.ts)9
-rw-r--r--packages/sol-cov/test/trace_test.ts57
-rw-r--r--packages/sol-resolver/CHANGELOG.json13
-rw-r--r--packages/sol-resolver/src/resolvers/fs_resolver.ts2
-rw-r--r--packages/sol-resolver/src/resolvers/name_resolver.ts11
-rw-r--r--packages/subproviders/src/index.ts1
-rw-r--r--packages/subproviders/src/utils/subprovider_utils.ts15
-rw-r--r--packages/types/CHANGELOG.json4
-rw-r--r--packages/types/src/index.ts13
-rw-r--r--packages/typescript-typings/types/web3-provider-engine/index.d.ts18
-rw-r--r--packages/utils/CHANGELOG.json9
-rw-r--r--packages/utils/package.json1
-rw-r--r--packages/utils/src/abi_decoder.ts13
-rw-r--r--packages/utils/src/address_utils.ts5
-rw-r--r--packages/utils/src/log_utils.ts3
52 files changed, 586 insertions, 205 deletions
diff --git a/packages/0x.js/test/artifacts_test.ts b/packages/0x.js/test/artifacts_test.ts
index ca554a4f5..982fb8e63 100644
--- a/packages/0x.js/test/artifacts_test.ts
+++ b/packages/0x.js/test/artifacts_test.ts
@@ -15,7 +15,7 @@ const TIMEOUT = 10000;
describe('Artifacts', () => {
describe('contracts are deployed on kovan', () => {
const kovanRpcUrl = constants.KOVAN_RPC_URL;
- const provider = web3Factory.create({ rpcUrl: kovanRpcUrl }).currentProvider;
+ const provider = web3Factory.getRpcProvider({ rpcUrl: kovanRpcUrl });
const config = {
networkId: constants.KOVAN_NETWORK_ID,
};
@@ -32,7 +32,7 @@ describe('Artifacts', () => {
});
describe('contracts are deployed on ropsten', () => {
const ropstenRpcUrl = constants.ROPSTEN_RPC_URL;
- const provider = web3Factory.create({ rpcUrl: ropstenRpcUrl }).currentProvider;
+ const provider = web3Factory.getRpcProvider({ rpcUrl: ropstenRpcUrl });
const config = {
networkId: constants.ROPSTEN_NETWORK_ID,
};
diff --git a/packages/0x.js/test/utils/web3_wrapper.ts b/packages/0x.js/test/utils/web3_wrapper.ts
index b0ccfa546..71a0dc1c2 100644
--- a/packages/0x.js/test/utils/web3_wrapper.ts
+++ b/packages/0x.js/test/utils/web3_wrapper.ts
@@ -2,8 +2,7 @@ import { devConstants, web3Factory } from '@0xproject/dev-utils';
import { Provider } from '@0xproject/types';
import { Web3Wrapper } from '@0xproject/web3-wrapper';
-const web3 = web3Factory.create({ shouldUseInProcessGanache: true });
-const provider: Provider = web3.currentProvider;
-const web3Wrapper = new Web3Wrapper(web3.currentProvider);
+const provider: Provider = web3Factory.getRpcProvider({ shouldUseInProcessGanache: true });
+const web3Wrapper = new Web3Wrapper(provider);
export { provider, web3Wrapper };
diff --git a/packages/contract-wrappers/test/artifacts_test.ts b/packages/contract-wrappers/test/artifacts_test.ts
index 446b8f9d1..eaaa89c48 100644
--- a/packages/contract-wrappers/test/artifacts_test.ts
+++ b/packages/contract-wrappers/test/artifacts_test.ts
@@ -15,7 +15,7 @@ const TIMEOUT = 10000;
describe('Artifacts', () => {
describe('contracts are deployed on kovan', () => {
const kovanRpcUrl = constants.KOVAN_RPC_URL;
- const provider = web3Factory.create({ rpcUrl: kovanRpcUrl }).currentProvider;
+ const provider = web3Factory.getRpcProvider({ rpcUrl: kovanRpcUrl });
const config = {
networkId: constants.KOVAN_NETWORK_ID,
};
@@ -32,7 +32,7 @@ describe('Artifacts', () => {
});
describe('contracts are deployed on ropsten', () => {
const ropstenRpcUrl = constants.ROPSTEN_RPC_URL;
- const provider = web3Factory.create({ rpcUrl: ropstenRpcUrl }).currentProvider;
+ const provider = web3Factory.getRpcProvider({ rpcUrl: ropstenRpcUrl });
const config = {
networkId: constants.ROPSTEN_NETWORK_ID,
};
diff --git a/packages/contract-wrappers/test/utils/web3_wrapper.ts b/packages/contract-wrappers/test/utils/web3_wrapper.ts
index b0ccfa546..71a0dc1c2 100644
--- a/packages/contract-wrappers/test/utils/web3_wrapper.ts
+++ b/packages/contract-wrappers/test/utils/web3_wrapper.ts
@@ -2,8 +2,7 @@ import { devConstants, web3Factory } from '@0xproject/dev-utils';
import { Provider } from '@0xproject/types';
import { Web3Wrapper } from '@0xproject/web3-wrapper';
-const web3 = web3Factory.create({ shouldUseInProcessGanache: true });
-const provider: Provider = web3.currentProvider;
-const web3Wrapper = new Web3Wrapper(web3.currentProvider);
+const provider: Provider = web3Factory.getRpcProvider({ shouldUseInProcessGanache: true });
+const web3Wrapper = new Web3Wrapper(provider);
export { provider, web3Wrapper };
diff --git a/packages/contracts/package.json b/packages/contracts/package.json
index be3ca3bc4..766280fc9 100644
--- a/packages/contracts/package.json
+++ b/packages/contracts/package.json
@@ -44,6 +44,8 @@
"@0xproject/abi-gen": "^0.3.0",
"@0xproject/dev-utils": "^0.4.2",
"@0xproject/tslint-config": "^0.4.18",
+ "@0xproject/subproviders": "^0.10.1",
+ "@0xproject/sol-cov": "^0.0.10",
"@types/lodash": "4.14.104",
"@types/node": "^8.0.53",
"@types/yargs": "^10.0.0",
diff --git a/packages/contracts/src/utils/web3_wrapper.ts b/packages/contracts/src/utils/web3_wrapper.ts
index ed1c488a2..02595506b 100644
--- a/packages/contracts/src/utils/web3_wrapper.ts
+++ b/packages/contracts/src/utils/web3_wrapper.ts
@@ -1,12 +1,19 @@
-import { devConstants, web3Factory } from '@0xproject/dev-utils';
+import { devConstants, env, EnvVars, web3Factory } from '@0xproject/dev-utils';
+import { prependSubprovider } from '@0xproject/subproviders';
import { Provider } from '@0xproject/types';
import { Web3Wrapper } from '@0xproject/web3-wrapper';
+import { coverage } from './coverage';
+
export const txDefaults = {
from: devConstants.TESTRPC_FIRST_ADDRESS,
gas: devConstants.GAS_ESTIMATE,
};
const providerConfigs = { shouldUseInProcessGanache: true };
-export const web3 = web3Factory.create(providerConfigs);
-export const provider = web3.currentProvider;
+export const provider = web3Factory.getRpcProvider(providerConfigs);
+const isCoverageEnabled = env.parseBoolean(EnvVars.SolidityCoverage);
+if (isCoverageEnabled) {
+ const coverageSubprovider = coverage.getCoverageSubproviderSingleton();
+ prependSubprovider(provider, coverageSubprovider);
+}
export const web3Wrapper = new Web3Wrapper(provider);
diff --git a/packages/contracts/test/global_hooks.ts b/packages/contracts/test/global_hooks.ts
index 089521d94..509dc6837 100644
--- a/packages/contracts/test/global_hooks.ts
+++ b/packages/contracts/test/global_hooks.ts
@@ -1,4 +1,6 @@
-import { coverage, env, EnvVars } from '@0xproject/dev-utils';
+import { env, EnvVars } from '@0xproject/dev-utils';
+
+import { coverage } from './utils/coverage';
after('generate coverage report', async () => {
if (env.parseBoolean(EnvVars.SolidityCoverage)) {
diff --git a/packages/contracts/test/utils/coverage.ts b/packages/contracts/test/utils/coverage.ts
new file mode 100644
index 000000000..a37939464
--- /dev/null
+++ b/packages/contracts/test/utils/coverage.ts
@@ -0,0 +1,21 @@
+import { devConstants } from '@0xproject/dev-utils';
+import { CoverageSubprovider, SolCompilerArtifactAdapter } from '@0xproject/sol-cov';
+import * as fs from 'fs';
+import * as _ from 'lodash';
+
+let coverageSubprovider: CoverageSubprovider;
+
+export const coverage = {
+ getCoverageSubproviderSingleton(): CoverageSubprovider {
+ if (_.isUndefined(coverageSubprovider)) {
+ coverageSubprovider = coverage._getCoverageSubprovider();
+ }
+ return coverageSubprovider;
+ },
+ _getCoverageSubprovider(): CoverageSubprovider {
+ const defaultFromAddress = devConstants.TESTRPC_FIRST_ADDRESS;
+ const solCompilerArtifactAdapter = new SolCompilerArtifactAdapter();
+ const subprovider = new CoverageSubprovider(solCompilerArtifactAdapter, defaultFromAddress);
+ return subprovider;
+ },
+};
diff --git a/packages/dev-utils/CHANGELOG.json b/packages/dev-utils/CHANGELOG.json
index 19f2591d2..ecb43a42e 100644
--- a/packages/dev-utils/CHANGELOG.json
+++ b/packages/dev-utils/CHANGELOG.json
@@ -3,6 +3,10 @@
"version": "0.4.2",
"changes": [
{
+ "note": "Pass SolCompilerArtifactAdapter to CoverageSubprovider",
+ "pr": 589
+ },
+ {
"note": "Move callbackErrorReporter over from 0x.js",
"pr": 579
}
diff --git a/packages/dev-utils/package.json b/packages/dev-utils/package.json
index 96180b2ce..0b11029f6 100644
--- a/packages/dev-utils/package.json
+++ b/packages/dev-utils/package.json
@@ -44,7 +44,6 @@
"typescript": "2.7.1"
},
"dependencies": {
- "@0xproject/sol-cov": "^0.0.11",
"@0xproject/subproviders": "^0.10.2",
"@0xproject/types": "^0.7.0",
"@0xproject/typescript-typings": "^0.3.2",
diff --git a/packages/dev-utils/src/coverage.ts b/packages/dev-utils/src/coverage.ts
deleted file mode 100644
index 6f7640835..000000000
--- a/packages/dev-utils/src/coverage.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-import { CoverageSubprovider } from '@0xproject/sol-cov';
-import * as _ from 'lodash';
-
-import { constants } from './constants';
-
-let coverageSubprovider: CoverageSubprovider;
-
-export const coverage = {
- getCoverageSubproviderSingleton(): CoverageSubprovider {
- if (_.isUndefined(coverageSubprovider)) {
- coverageSubprovider = coverage._getCoverageSubprovider();
- }
- return coverageSubprovider;
- },
- _getCoverageSubprovider(): CoverageSubprovider {
- const artifactsPath = '../migrations/artifacts/1.0.0';
- const contractsPath = 'src/contracts';
- const defaultFromAddress = constants.TESTRPC_FIRST_ADDRESS;
- return new CoverageSubprovider(artifactsPath, contractsPath, defaultFromAddress);
- },
-};
diff --git a/packages/dev-utils/src/index.ts b/packages/dev-utils/src/index.ts
index 9124f3e28..d4c19f1bf 100644
--- a/packages/dev-utils/src/index.ts
+++ b/packages/dev-utils/src/index.ts
@@ -1,6 +1,5 @@
export { BlockchainLifecycle } from './blockchain_lifecycle';
export { web3Factory } from './web3_factory';
export { constants as devConstants } from './constants';
-export { coverage } from './coverage';
export { env, EnvVars } from './env';
export { callbackErrorReporter } from './callback_error_reporter';
diff --git a/packages/dev-utils/src/web3_factory.ts b/packages/dev-utils/src/web3_factory.ts
index 4cd343c44..5b32d3930 100644
--- a/packages/dev-utils/src/web3_factory.ts
+++ b/packages/dev-utils/src/web3_factory.ts
@@ -13,16 +13,8 @@ import * as _ from 'lodash';
import * as process from 'process';
import { constants } from './constants';
-import { coverage } from './coverage';
import { env, EnvVars } from './env';
-// HACK: web3 leaks XMLHttpRequest into the global scope and causes requests to hang
-// because they are using the wrong XHR package.
-// importing web3 after subproviders fixes this issue
-// Filed issue: https://github.com/ethereum/web3.js/issues/844
-// tslint:disable-next-line:ordered-imports
-import * as Web3 from 'web3';
-
export interface Web3Config {
hasAddresses?: boolean; // default: true
shouldUseInProcessGanache?: boolean; // default: false
@@ -30,18 +22,8 @@ export interface Web3Config {
}
export const web3Factory = {
- create(config: Web3Config = {}): Web3 {
- const provider = this.getRpcProvider(config);
- const web3 = new Web3();
- web3.setProvider(provider);
- return web3;
- },
- getRpcProvider(config: Web3Config = {}): Provider {
+ getRpcProvider(config: Web3Config = {}): ProviderEngine {
const provider = new ProviderEngine();
- const isCoverageEnabled = env.parseBoolean(EnvVars.SolidityCoverage);
- if (isCoverageEnabled) {
- provider.addProvider(coverage.getCoverageSubproviderSingleton());
- }
const hasAddresses = _.isUndefined(config.hasAddresses) || config.hasAddresses;
if (!hasAddresses) {
provider.addProvider(new EmptyWalletSubprovider());
diff --git a/packages/metacoin/test/utils/config.ts b/packages/metacoin/test/utils/config.ts
index 389edb388..ef4932845 100644
--- a/packages/metacoin/test/utils/config.ts
+++ b/packages/metacoin/test/utils/config.ts
@@ -3,8 +3,8 @@ import * as path from 'path';
export const config = {
networkId: 50,
- artifactsDir: path.resolve(__dirname, '../../artifacts'),
- contractsDir: path.resolve(__dirname, '../../contracts'),
+ artifactsDir: 'artifacts',
+ contractsDir: 'contracts',
ganacheLogFile: 'ganache.log',
txDefaults: {
from: devConstants.TESTRPC_FIRST_ADDRESS,
diff --git a/packages/metacoin/test/utils/coverage.ts b/packages/metacoin/test/utils/coverage.ts
index debd544ed..945afb0a7 100644
--- a/packages/metacoin/test/utils/coverage.ts
+++ b/packages/metacoin/test/utils/coverage.ts
@@ -1,5 +1,5 @@
import { devConstants } from '@0xproject/dev-utils';
-import { CoverageSubprovider } from '@0xproject/sol-cov';
+import { CoverageSubprovider, SolCompilerArtifactAdapter } from '@0xproject/sol-cov';
import * as _ from 'lodash';
import { config } from './config';
@@ -15,6 +15,7 @@ export const coverage = {
},
_getCoverageSubprovider(): CoverageSubprovider {
const defaultFromAddress = devConstants.TESTRPC_FIRST_ADDRESS;
- return new CoverageSubprovider(config.artifactsDir, config.contractsDir, defaultFromAddress);
+ const zeroExArtifactsAdapter = new SolCompilerArtifactAdapter(config.artifactsDir, config.contractsDir);
+ return new CoverageSubprovider(zeroExArtifactsAdapter, defaultFromAddress);
},
};
diff --git a/packages/metacoin/test/utils/web3_wrapper.ts b/packages/metacoin/test/utils/web3_wrapper.ts
index b4bb61f09..724ed4e1f 100644
--- a/packages/metacoin/test/utils/web3_wrapper.ts
+++ b/packages/metacoin/test/utils/web3_wrapper.ts
@@ -1,5 +1,5 @@
import { env, EnvVars } from '@0xproject/dev-utils';
-import { GanacheSubprovider } from '@0xproject/subproviders';
+import { GanacheSubprovider, prependSubprovider } from '@0xproject/subproviders';
import { Web3Wrapper } from '@0xproject/web3-wrapper';
import * as fs from 'fs';
import * as _ from 'lodash';
@@ -9,10 +9,6 @@ import { config } from './config';
import { coverage } from './coverage';
export const provider = new ProviderEngine();
-const isCoverageEnabled = env.parseBoolean(EnvVars.SolidityCoverage);
-if (isCoverageEnabled) {
- provider.addProvider(coverage.getCoverageSubproviderSingleton());
-}
provider.addProvider(
new GanacheSubprovider({
logger: {
@@ -27,4 +23,10 @@ provider.addProvider(
);
provider.start();
+const isCoverageEnabled = env.parseBoolean(EnvVars.SolidityCoverage);
+if (isCoverageEnabled) {
+ const coverageSubprovider = coverage.getCoverageSubproviderSingleton();
+ prependSubprovider(provider, coverageSubprovider);
+}
+
export const web3Wrapper = new Web3Wrapper(provider);
diff --git a/packages/migrations/package.json b/packages/migrations/package.json
index 6d8ff591c..08f7aa6b2 100644
--- a/packages/migrations/package.json
+++ b/packages/migrations/package.json
@@ -9,7 +9,7 @@
"types": "lib/index.d.ts",
"scripts": {
"watch": "tsc -w",
- "prebuild": "run-s clean compile copy_artifacts generate_contract_wrappers",
+ "prebuild": "run-s clean copy_artifacts generate_contract_wrappers",
"copy_artifacts": "copyfiles 'artifacts/1.0.0/**/*' ./lib",
"build": "tsc",
"clean": "shx rm -rf lib src/contract_wrappers",
diff --git a/packages/migrations/src/migrate.ts b/packages/migrations/src/migrate.ts
index b00ba698f..1230f376e 100644
--- a/packages/migrations/src/migrate.ts
+++ b/packages/migrations/src/migrate.ts
@@ -11,8 +11,7 @@ import { runMigrationsAsync } from './migration';
from: devConstants.TESTRPC_FIRST_ADDRESS,
};
const providerConfigs = { shouldUseInProcessGanache: false };
- const web3 = web3Factory.create(providerConfigs);
- const provider = web3.currentProvider;
+ const provider: Provider = web3Factory.getRpcProvider(providerConfigs);
const artifactsDir = 'artifacts/1.0.0';
await runMigrationsAsync(provider, artifactsDir, txDefaults);
process.exit(0);
diff --git a/packages/order-utils/test/utils/web3_wrapper.ts b/packages/order-utils/test/utils/web3_wrapper.ts
index b0ccfa546..71a0dc1c2 100644
--- a/packages/order-utils/test/utils/web3_wrapper.ts
+++ b/packages/order-utils/test/utils/web3_wrapper.ts
@@ -2,8 +2,7 @@ import { devConstants, web3Factory } from '@0xproject/dev-utils';
import { Provider } from '@0xproject/types';
import { Web3Wrapper } from '@0xproject/web3-wrapper';
-const web3 = web3Factory.create({ shouldUseInProcessGanache: true });
-const provider: Provider = web3.currentProvider;
-const web3Wrapper = new Web3Wrapper(web3.currentProvider);
+const provider: Provider = web3Factory.getRpcProvider({ shouldUseInProcessGanache: true });
+const web3Wrapper = new Web3Wrapper(provider);
export { provider, web3Wrapper };
diff --git a/packages/order-watcher/test/utils/web3_wrapper.ts b/packages/order-watcher/test/utils/web3_wrapper.ts
index b0ccfa546..71a0dc1c2 100644
--- a/packages/order-watcher/test/utils/web3_wrapper.ts
+++ b/packages/order-watcher/test/utils/web3_wrapper.ts
@@ -2,8 +2,7 @@ import { devConstants, web3Factory } from '@0xproject/dev-utils';
import { Provider } from '@0xproject/types';
import { Web3Wrapper } from '@0xproject/web3-wrapper';
-const web3 = web3Factory.create({ shouldUseInProcessGanache: true });
-const provider: Provider = web3.currentProvider;
-const web3Wrapper = new Web3Wrapper(web3.currentProvider);
+const provider: Provider = web3Factory.getRpcProvider({ shouldUseInProcessGanache: true });
+const web3Wrapper = new Web3Wrapper(provider);
export { provider, web3Wrapper };
diff --git a/packages/sol-compiler/CHANGELOG.json b/packages/sol-compiler/CHANGELOG.json
index c558a98c5..33fd99e4f 100644
--- a/packages/sol-compiler/CHANGELOG.json
+++ b/packages/sol-compiler/CHANGELOG.json
@@ -5,6 +5,10 @@
{
"note": "Properly export the executable binary",
"pr": 588
+ },
+ {
+ "note": "Add the ability to define a specific solidity version",
+ "pr": 589
}
],
"timestamp": 1527009133
diff --git a/packages/sol-compiler/src/compiler.ts b/packages/sol-compiler/src/compiler.ts
index c17616246..2ebc5228e 100644
--- a/packages/sol-compiler/src/compiler.ts
+++ b/packages/sol-compiler/src/compiler.ts
@@ -74,6 +74,7 @@ export class Compiler {
private _contractsDir: string;
private _compilerSettings: solc.CompilerSettings;
private _artifactsDir: string;
+ private _solcVersionIfExists: string | undefined;
private _specifiedContracts: string[] | TYPE_ALL_FILES_IDENTIFIER;
/**
* Instantiates a new instance of the Compiler class.
@@ -85,6 +86,7 @@ export class Compiler {
? JSON.parse(fs.readFileSync(CONFIG_FILE).toString())
: {};
this._contractsDir = opts.contractsDir || config.contractsDir || DEFAULT_CONTRACTS_DIR;
+ this._solcVersionIfExists = opts.solcVersion || config.solcVersion;
this._compilerSettings = opts.compilerSettings || config.compilerSettings || DEFAULT_COMPILER_SETTINGS;
this._artifactsDir = opts.artifactsDir || config.artifactsDir || DEFAULT_ARTIFACTS_DIR;
this._specifiedContracts = opts.contracts || config.contracts || ALL_CONTRACTS_IDENTIFIER;
@@ -139,9 +141,12 @@ export class Compiler {
if (!shouldCompile) {
return;
}
- const solcVersionRange = parseSolidityVersionRange(contractSource.source);
- const availableCompilerVersions = _.keys(binPaths);
- const solcVersion = semver.maxSatisfying(availableCompilerVersions, solcVersionRange);
+ let solcVersion = this._solcVersionIfExists;
+ if (_.isUndefined(solcVersion)) {
+ const solcVersionRange = parseSolidityVersionRange(contractSource.source);
+ const availableCompilerVersions = _.keys(binPaths);
+ solcVersion = semver.maxSatisfying(availableCompilerVersions, solcVersionRange);
+ }
const fullSolcVersion = binPaths[solcVersion];
const compilerBinFilename = path.join(SOLC_BIN_DIR, fullSolcVersion);
let solcjs: string;
@@ -229,7 +234,7 @@ export class Compiler {
sourceTreeHashHex,
compiler: {
name: 'solc',
- version: solcVersion,
+ version: fullSolcVersion,
settings: this._compilerSettings,
},
};
diff --git a/packages/sol-compiler/src/index.ts b/packages/sol-compiler/src/index.ts
index 4b4c51de2..15c166992 100644
--- a/packages/sol-compiler/src/index.ts
+++ b/packages/sol-compiler/src/index.ts
@@ -1,2 +1,3 @@
export { Compiler } from './compiler';
+export { CompilerOptions } from './utils/types';
export { ContractArtifact, ContractNetworks } from './utils/types';
diff --git a/packages/sol-compiler/src/utils/types.ts b/packages/sol-compiler/src/utils/types.ts
index b12a11b79..d43347fa6 100644
--- a/packages/sol-compiler/src/utils/types.ts
+++ b/packages/sol-compiler/src/utils/types.ts
@@ -55,6 +55,7 @@ export interface CompilerOptions {
artifactsDir?: string;
compilerSettings?: solc.CompilerSettings;
contracts?: string[] | '*';
+ solcVersion?: string;
}
export interface ContractSourceData {
diff --git a/packages/sol-compiler/test/util/provider.ts b/packages/sol-compiler/test/util/provider.ts
index e0fcb362a..2bd178129 100644
--- a/packages/sol-compiler/test/util/provider.ts
+++ b/packages/sol-compiler/test/util/provider.ts
@@ -3,7 +3,6 @@ import { Provider } from '@0xproject/types';
import * as Web3 from 'web3';
const providerConfigs = { shouldUseInProcessGanache: true };
-const web3Instance = web3Factory.create(providerConfigs);
-const provider: Provider = web3Instance.currentProvider;
+const provider: Provider = web3Factory.getRpcProvider(providerConfigs);
export { provider };
diff --git a/packages/sol-cov/CHANGELOG.json b/packages/sol-cov/CHANGELOG.json
index 167d5077e..0d3303231 100644
--- a/packages/sol-cov/CHANGELOG.json
+++ b/packages/sol-cov/CHANGELOG.json
@@ -1,6 +1,28 @@
[
{
"timestamp": 1527009134,
+ "version": "0.1.0",
+ "changes": [
+ {
+ "note": "Add artifact adapter as a parameter for CoverageSubprovider. Export AbstractArtifactAdapter",
+ "pr": 589
+ },
+ {
+ "note": "Implement SolCompilerArtifactAdapter and TruffleArtifactAdapter",
+ "pr": 589
+ },
+ {
+ "note": "Properly parse multi-level traces",
+ "pr": 589
+ },
+ {
+ "note": "Add support for solidity libraries",
+ "pr": 589
+ }
+ ]
+ },
+ {
+ "timestamp": 1527009133,
"version": "0.0.11",
"changes": [
{
diff --git a/packages/sol-cov/package.json b/packages/sol-cov/package.json
index f3c8ab67e..74ffa72bd 100644
--- a/packages/sol-cov/package.json
+++ b/packages/sol-cov/package.json
@@ -46,6 +46,7 @@
},
"homepage": "https://github.com/0xProject/0x.js/packages/sol-cov/README.md",
"dependencies": {
+ "@0xproject/sol-compiler": "^0.5.0",
"@0xproject/subproviders": "^0.10.2",
"@0xproject/types": "^0.7.0",
"@0xproject/typescript-typings": "^0.3.2",
@@ -54,7 +55,9 @@
"glob": "^7.1.2",
"istanbul": "^0.4.5",
"lodash": "^4.17.4",
+ "loglevel": "^1.6.1",
"mkdirp": "^0.5.1",
+ "rimraf": "^2.6.2",
"semaphore-async-await": "^1.5.1",
"solidity-parser-antlr": "^0.2.8"
},
@@ -62,9 +65,11 @@
"@0xproject/monorepo-scripts": "^0.1.20",
"@0xproject/tslint-config": "^0.4.18",
"@types/istanbul": "^0.4.30",
+ "@types/loglevel": "^1.5.3",
"@types/mkdirp": "^0.5.1",
"@types/mocha": "^2.2.42",
"@types/node": "^8.0.53",
+ "@types/rimraf": "^2.0.2",
"chai": "^4.0.1",
"copyfiles": "^1.2.0",
"dirty-chai": "^2.0.1",
diff --git a/packages/sol-cov/src/artifact_adapters/abstract_artifact_adapter.ts b/packages/sol-cov/src/artifact_adapters/abstract_artifact_adapter.ts
new file mode 100644
index 000000000..fcc6562ad
--- /dev/null
+++ b/packages/sol-cov/src/artifact_adapters/abstract_artifact_adapter.ts
@@ -0,0 +1,5 @@
+import { ContractData } from '../types';
+
+export abstract class AbstractArtifactAdapter {
+ public abstract async collectContractsDataAsync(): Promise<ContractData[]>;
+}
diff --git a/packages/sol-cov/src/artifact_adapters/sol_compiler_artifact_adapter.ts b/packages/sol-cov/src/artifact_adapters/sol_compiler_artifact_adapter.ts
new file mode 100644
index 000000000..d08828bf6
--- /dev/null
+++ b/packages/sol-cov/src/artifact_adapters/sol_compiler_artifact_adapter.ts
@@ -0,0 +1,49 @@
+import * as fs from 'fs';
+import * as glob from 'glob';
+import * as _ from 'lodash';
+import * as path from 'path';
+
+import { ContractData } from '../types';
+
+import { AbstractArtifactAdapter } from './abstract_artifact_adapter';
+
+const CONFIG_FILE = 'compiler.json';
+
+export class SolCompilerArtifactAdapter extends AbstractArtifactAdapter {
+ private _artifactsPath: string;
+ private _sourcesPath: string;
+ constructor(artifactsPath?: string, sourcesPath?: string) {
+ super();
+ const config = JSON.parse(fs.readFileSync(CONFIG_FILE).toString());
+ if (_.isUndefined(artifactsPath) && _.isUndefined(config.artifactsDir)) {
+ throw new Error(`artifactsDir not found in ${CONFIG_FILE}`);
+ }
+ this._artifactsPath = config.artifactsDir;
+ if (_.isUndefined(sourcesPath) && _.isUndefined(config.contractsDir)) {
+ throw new Error(`contractsDir not found in ${CONFIG_FILE}`);
+ }
+ this._sourcesPath = config.contractsDir;
+ }
+ public async collectContractsDataAsync(): Promise<ContractData[]> {
+ const artifactsGlob = `${this._artifactsPath}/**/*.json`;
+ const artifactFileNames = glob.sync(artifactsGlob, { absolute: true });
+ const contractsData: ContractData[] = [];
+ for (const artifactFileName of artifactFileNames) {
+ const artifact = JSON.parse(fs.readFileSync(artifactFileName).toString());
+ let sources = _.keys(artifact.sources);
+ sources = _.map(sources, relativeFilePath => path.resolve(this._sourcesPath, relativeFilePath));
+ const contractName = artifact.contractName;
+ const sourceCodes = _.map(sources, (source: string) => fs.readFileSync(source).toString());
+ const contractData = {
+ sourceCodes,
+ sources,
+ bytecode: artifact.compilerOutput.evm.bytecode.object,
+ sourceMap: artifact.compilerOutput.evm.bytecode.sourceMap,
+ runtimeBytecode: artifact.compilerOutput.evm.deployedBytecode.object,
+ sourceMapRuntime: artifact.compilerOutput.evm.deployedBytecode.sourceMap,
+ };
+ contractsData.push(contractData);
+ }
+ return contractsData;
+ }
+}
diff --git a/packages/sol-cov/src/artifact_adapters/truffle_artifact_adapter.ts b/packages/sol-cov/src/artifact_adapters/truffle_artifact_adapter.ts
new file mode 100644
index 000000000..c7f21b6eb
--- /dev/null
+++ b/packages/sol-cov/src/artifact_adapters/truffle_artifact_adapter.ts
@@ -0,0 +1,43 @@
+import { Compiler, CompilerOptions } from '@0xproject/sol-compiler';
+import * as fs from 'fs';
+import * as glob from 'glob';
+import * as _ from 'lodash';
+import * as path from 'path';
+import * as rimraf from 'rimraf';
+
+import { ContractData } from '../types';
+
+import { AbstractArtifactAdapter } from './abstract_artifact_adapter';
+import { SolCompilerArtifactAdapter } from './sol_compiler_artifact_adapter';
+
+export class TruffleArtifactAdapter extends AbstractArtifactAdapter {
+ private _solcVersion: string;
+ private _sourcesPath: string;
+ constructor(sourcesPath: string, solcVersion: string) {
+ super();
+ this._solcVersion = solcVersion;
+ this._sourcesPath = sourcesPath;
+ }
+ public async collectContractsDataAsync(): Promise<ContractData[]> {
+ const artifactsDir = '.0x-artifacts';
+ const compilerOptions: CompilerOptions = {
+ contractsDir: this._sourcesPath,
+ artifactsDir,
+ compilerSettings: {
+ outputSelection: {
+ ['*']: {
+ ['*']: ['abi', 'evm.bytecode.object', 'evm.deployedBytecode.object'],
+ },
+ },
+ },
+ contracts: '*',
+ solcVersion: this._solcVersion,
+ };
+ const compiler = new Compiler(compilerOptions);
+ await compiler.compileAsync();
+ const solCompilerArtifactAdapter = new SolCompilerArtifactAdapter(artifactsDir, this._sourcesPath);
+ const contractsDataFrom0xArtifacts = await solCompilerArtifactAdapter.collectContractsDataAsync();
+ rimraf.sync(artifactsDir);
+ return contractsDataFrom0xArtifacts;
+ }
+}
diff --git a/packages/sol-cov/src/collect_contract_data.ts b/packages/sol-cov/src/collect_contract_data.ts
deleted file mode 100644
index 2c2a12835..000000000
--- a/packages/sol-cov/src/collect_contract_data.ts
+++ /dev/null
@@ -1,31 +0,0 @@
-import * as fs from 'fs';
-import * as glob from 'glob';
-import * as _ from 'lodash';
-import * as path from 'path';
-
-import { ContractData } from './types';
-
-export const collectContractsData = (artifactsPath: string, sourcesPath: string) => {
- const artifactsGlob = `${artifactsPath}/**/*.json`;
- const artifactFileNames = glob.sync(artifactsGlob, { absolute: true });
- const contractsData: ContractData[] = [];
- _.forEach(artifactFileNames, artifactFileName => {
- const artifact = JSON.parse(fs.readFileSync(artifactFileName).toString());
- const sources = _.keys(artifact.sources);
- const contractName = artifact.contractName;
- // We don't compute coverage for dependencies
- const sourceCodes = _.map(sources, (source: string) =>
- fs.readFileSync(path.join(sourcesPath, source)).toString(),
- );
- const contractData = {
- sourceCodes,
- sources,
- bytecode: artifact.compilerOutput.evm.bytecode.object,
- sourceMap: artifact.compilerOutput.evm.bytecode.sourceMap,
- runtimeBytecode: artifact.compilerOutput.evm.deployedBytecode.object,
- sourceMapRuntime: artifact.compilerOutput.evm.deployedBytecode.sourceMap,
- };
- contractsData.push(contractData);
- });
- return contractsData;
-};
diff --git a/packages/sol-cov/src/constants.ts b/packages/sol-cov/src/constants.ts
index 64d2228a3..34d62b537 100644
--- a/packages/sol-cov/src/constants.ts
+++ b/packages/sol-cov/src/constants.ts
@@ -1,6 +1,6 @@
// tslint:disable:number-literal-format
export const constants = {
- NEW_CONTRACT: 'NEW_CONTRACT',
+ NEW_CONTRACT: 'NEW_CONTRACT' as 'NEW_CONTRACT',
PUSH1: 0x60,
PUSH2: 0x61,
PUSH32: 0x7f,
diff --git a/packages/sol-cov/src/coverage_manager.ts b/packages/sol-cov/src/coverage_manager.ts
index 800ca96dd..31b0e6fbc 100644
--- a/packages/sol-cov/src/coverage_manager.ts
+++ b/packages/sol-cov/src/coverage_manager.ts
@@ -1,12 +1,13 @@
import { promisify } from '@0xproject/utils';
-import { addHexPrefix } from 'ethereumjs-util';
+import { addHexPrefix, stripHexPrefix } from 'ethereumjs-util';
import * as fs from 'fs';
import { Collector } from 'istanbul';
import * as _ from 'lodash';
+import { getLogger, levels, Logger, LogLevel } from 'loglevel';
import * as mkdirp from 'mkdirp';
import * as path from 'path';
-import { collectContractsData } from './collect_contract_data';
+import { AbstractArtifactAdapter } from './artifact_adapters/abstract_artifact_adapter';
import { collectCoverageEntries } from './collect_coverage_entries';
import { constants } from './constants';
import { parseSourceMap } from './source_maps';
@@ -34,41 +35,23 @@ import { utils } from './utils';
const mkdirpAsync = promisify<undefined>(mkdirp);
export class CoverageManager {
- private _sourcesPath: string;
+ private _artifactAdapter: AbstractArtifactAdapter;
+ private _logger: Logger;
private _traceInfos: TraceInfo[] = [];
- private _contractsData: ContractData[] = [];
private _getContractCodeAsync: (address: string) => Promise<string>;
- constructor(
- artifactsPath: string,
- sourcesPath: string,
- getContractCodeAsync: (address: string) => Promise<string>,
- ) {
- this._getContractCodeAsync = getContractCodeAsync;
- this._sourcesPath = sourcesPath;
- this._contractsData = collectContractsData(artifactsPath, this._sourcesPath);
- }
- public appendTraceInfo(traceInfo: TraceInfo): void {
- this._traceInfos.push(traceInfo);
- }
- public async writeCoverageAsync(): Promise<void> {
- const finalCoverage = await this._computeCoverageAsync();
- const stringifiedCoverage = JSON.stringify(finalCoverage, null, '\t');
- await mkdirpAsync('coverage');
- fs.writeFileSync('coverage/coverage.json', stringifiedCoverage);
- }
- private _getSingleFileCoverageForTrace(
+ private static _getSingleFileCoverageForTrace(
contractData: ContractData,
coveredPcs: number[],
pcToSourceRange: { [programCounter: number]: SourceRange },
fileIndex: number,
): Coverage {
- const fileName = contractData.sources[fileIndex];
+ const absoluteFileName = contractData.sources[fileIndex];
const coverageEntriesDescription = collectCoverageEntries(contractData.sourceCodes[fileIndex]);
let sourceRanges = _.map(coveredPcs, coveredPc => pcToSourceRange[coveredPc]);
sourceRanges = _.compact(sourceRanges); // Some PC's don't map to a source range and we just ignore them.
// By default lodash does a shallow object comparasion. We JSON.stringify them and compare as strings.
sourceRanges = _.uniqBy(sourceRanges, s => JSON.stringify(s)); // We don't care if one PC was covered multiple times within a single transaction
- sourceRanges = _.filter(sourceRanges, sourceRange => sourceRange.fileName === fileName);
+ sourceRanges = _.filter(sourceRanges, sourceRange => sourceRange.fileName === absoluteFileName);
const branchCoverage: BranchCoverage = {};
const branchIds = _.keys(coverageEntriesDescription.branchMap);
for (const branchId of branchIds) {
@@ -118,7 +101,6 @@ export class CoverageManager {
);
statementCoverage[modifierStatementId] = isModifierCovered;
}
- const absoluteFileName = path.join(this._sourcesPath, fileName);
const partialCoverage = {
[absoluteFileName]: {
...coverageEntriesDescription,
@@ -131,18 +113,63 @@ export class CoverageManager {
};
return partialCoverage;
}
+ private static _bytecodeToBytecodeRegex(bytecode: string): string {
+ const bytecodeRegex = bytecode
+ // Library linking placeholder: __ConvertLib____________________________
+ .replace(/_.*_/, '.*')
+ // Last 86 characters is solidity compiler metadata that's different between compilations
+ .replace(/.{86}$/, '')
+ // Libraries contain their own address at the beginning of the code and it's impossible to know it in advance
+ .replace(/^0x730000000000000000000000000000000000000000/, '0x73........................................');
+ return bytecodeRegex;
+ }
+ private static _getContractDataIfExists(contractsData: ContractData[], bytecode: string): ContractData | undefined {
+ if (!bytecode.startsWith('0x')) {
+ throw new Error(`0x hex prefix missing: ${bytecode}`);
+ }
+ const contractData = _.find(contractsData, contractDataCandidate => {
+ const bytecodeRegex = CoverageManager._bytecodeToBytecodeRegex(contractDataCandidate.bytecode);
+ const runtimeBytecodeRegex = CoverageManager._bytecodeToBytecodeRegex(
+ contractDataCandidate.runtimeBytecode,
+ );
+ // We use that function to find by bytecode or runtimeBytecode. Those are quasi-random strings so
+ // collisions are practically impossible and it allows us to reuse that code
+ return !_.isNull(bytecode.match(bytecodeRegex)) || !_.isNull(bytecode.match(runtimeBytecodeRegex));
+ });
+ return contractData;
+ }
+ constructor(
+ artifactAdapter: AbstractArtifactAdapter,
+ getContractCodeAsync: (address: string) => Promise<string>,
+ isVerbose: boolean,
+ ) {
+ this._getContractCodeAsync = getContractCodeAsync;
+ this._artifactAdapter = artifactAdapter;
+ this._logger = getLogger('sol-cov');
+ this._logger.setLevel(isVerbose ? levels.TRACE : levels.ERROR);
+ }
+ public appendTraceInfo(traceInfo: TraceInfo): void {
+ this._traceInfos.push(traceInfo);
+ }
+ public async writeCoverageAsync(): Promise<void> {
+ const finalCoverage = await this._computeCoverageAsync();
+ const stringifiedCoverage = JSON.stringify(finalCoverage, null, '\t');
+ await mkdirpAsync('coverage');
+ fs.writeFileSync('coverage/coverage.json', stringifiedCoverage);
+ }
private async _computeCoverageAsync(): Promise<Coverage> {
+ const contractsData = await this._artifactAdapter.collectContractsDataAsync();
const collector = new Collector();
for (const traceInfo of this._traceInfos) {
if (traceInfo.address !== constants.NEW_CONTRACT) {
// Runtime transaction
- let runtimeBytecode = (traceInfo as TraceInfoExistingContract).runtimeBytecode;
- runtimeBytecode = addHexPrefix(runtimeBytecode);
- const contractData = _.find(this._contractsData, { runtimeBytecode }) as ContractData;
+ const runtimeBytecode = (traceInfo as TraceInfoExistingContract).runtimeBytecode;
+ const contractData = CoverageManager._getContractDataIfExists(contractsData, runtimeBytecode);
if (_.isUndefined(contractData)) {
- throw new Error(`Transaction to an unknown address: ${traceInfo.address}`);
+ this._logger.warn(`Transaction to an unknown address: ${traceInfo.address}`);
+ continue;
}
- const bytecodeHex = contractData.runtimeBytecode.slice(2);
+ const bytecodeHex = stripHexPrefix(runtimeBytecode);
const sourceMap = contractData.sourceMapRuntime;
const pcToSourceRange = parseSourceMap(
contractData.sourceCodes,
@@ -151,7 +178,7 @@ export class CoverageManager {
contractData.sources,
);
for (let fileIndex = 0; fileIndex < contractData.sources.length; fileIndex++) {
- const singleFileCoverageForTrace = this._getSingleFileCoverageForTrace(
+ const singleFileCoverageForTrace = CoverageManager._getSingleFileCoverageForTrace(
contractData,
traceInfo.coveredPcs,
pcToSourceRange,
@@ -161,15 +188,13 @@ export class CoverageManager {
}
} else {
// Contract creation transaction
- let bytecode = (traceInfo as TraceInfoNewContract).bytecode;
- bytecode = addHexPrefix(bytecode);
- const contractData = _.find(this._contractsData, contractDataCandidate =>
- bytecode.startsWith(contractDataCandidate.bytecode),
- ) as ContractData;
+ const bytecode = (traceInfo as TraceInfoNewContract).bytecode;
+ const contractData = CoverageManager._getContractDataIfExists(contractsData, bytecode);
if (_.isUndefined(contractData)) {
- throw new Error(`Unknown contract creation transaction`);
+ this._logger.warn(`Unknown contract creation transaction`);
+ continue;
}
- const bytecodeHex = contractData.bytecode.slice(2);
+ const bytecodeHex = stripHexPrefix(bytecode);
const sourceMap = contractData.sourceMap;
const pcToSourceRange = parseSourceMap(
contractData.sourceCodes,
@@ -178,7 +203,7 @@ export class CoverageManager {
contractData.sources,
);
for (let fileIndex = 0; fileIndex < contractData.sources.length; fileIndex++) {
- const singleFileCoverageForTrace = this._getSingleFileCoverageForTrace(
+ const singleFileCoverageForTrace = CoverageManager._getSingleFileCoverageForTrace(
contractData,
traceInfo.coveredPcs,
pcToSourceRange,
diff --git a/packages/sol-cov/src/coverage_subprovider.ts b/packages/sol-cov/src/coverage_subprovider.ts
index 08efeaa24..438339a3f 100644
--- a/packages/sol-cov/src/coverage_subprovider.ts
+++ b/packages/sol-cov/src/coverage_subprovider.ts
@@ -1,11 +1,14 @@
import { Callback, ErrorCallback, NextCallback, Subprovider } from '@0xproject/subproviders';
import { BlockParam, CallData, JSONRPCRequestPayload, TransactionTrace, TxData } from '@0xproject/types';
+import * as fs from 'fs';
import * as _ from 'lodash';
import { Lock } from 'semaphore-async-await';
+import { AbstractArtifactAdapter } from './artifact_adapters/abstract_artifact_adapter';
import { constants } from './constants';
import { CoverageManager } from './coverage_manager';
-import { TraceInfoExistingContract, TraceInfoNewContract } from './types';
+import { getTracesByContractAddress } from './trace';
+import { BlockParamLiteral, TraceInfoExistingContract, TraceInfoNewContract } from './types';
interface MaybeFakeTxData extends TxData {
isFakeTransaction?: boolean;
@@ -26,15 +29,15 @@ export class CoverageSubprovider extends Subprovider {
private _defaultFromAddress: string;
/**
* Instantiates a CoverageSubprovider instance
- * @param artifactsPath Path to the smart contract artifacts
- * @param sourcesPath Path to the smart contract source files
+ * @param artifactAdapter Adapter for used artifacts format (0x, truffle, giveth, etc.)
* @param defaultFromAddress default from address to use when sending transactions
+ * @param isVerbose If true, we will log any unknown transactions. Otherwise we will ignore them
*/
- constructor(artifactsPath: string, sourcesPath: string, defaultFromAddress: string) {
+ constructor(artifactAdapter: AbstractArtifactAdapter, defaultFromAddress: string, isVerbose: boolean = true) {
super();
this._lock = new Lock();
this._defaultFromAddress = defaultFromAddress;
- this._coverageManager = new CoverageManager(artifactsPath, sourcesPath, this._getContractCodeAsync.bind(this));
+ this._coverageManager = new CoverageManager(artifactAdapter, this._getContractCodeAsync.bind(this), isVerbose);
}
/**
* Write the test coverage results to a file in Istanbul format.
@@ -86,7 +89,7 @@ export class CoverageSubprovider extends Subprovider {
} else {
const payload = {
method: 'eth_getBlockByNumber',
- params: ['latest', true],
+ params: [BlockParamLiteral.Latest, true],
};
const jsonRPCResponsePayload = await this.emitPayloadAsync(payload);
const transactions = jsonRPCResponsePayload.result.transactions;
@@ -115,29 +118,54 @@ export class CoverageSubprovider extends Subprovider {
private async _recordTxTraceAsync(address: string, data: string | undefined, txHash: string): Promise<void> {
let payload = {
method: 'debug_traceTransaction',
- params: [txHash, { disableMemory: true, disableStack: true, disableStorage: true }], // TODO For now testrpc just ignores those parameters https://github.com/trufflesuite/ganache-cli/issues/489
+ params: [txHash, { disableMemory: true, disableStack: false, disableStorage: true }],
};
- const jsonRPCResponsePayload = await this.emitPayloadAsync(payload);
+ let jsonRPCResponsePayload = await this.emitPayloadAsync(payload);
const trace: TransactionTrace = jsonRPCResponsePayload.result;
- const coveredPcs = _.map(trace.structLogs, log => log.pc);
+ const tracesByContractAddress = getTracesByContractAddress(trace.structLogs, address);
+ const subcallAddresses = _.keys(tracesByContractAddress);
if (address === constants.NEW_CONTRACT) {
- const traceInfo: TraceInfoNewContract = {
- coveredPcs,
- txHash,
- address: address as 'NEW_CONTRACT',
- bytecode: data as string,
- };
- this._coverageManager.appendTraceInfo(traceInfo);
+ for (const subcallAddress of subcallAddresses) {
+ let traceInfo: TraceInfoNewContract | TraceInfoExistingContract;
+ if (subcallAddress === 'NEW_CONTRACT') {
+ const traceForThatSubcall = tracesByContractAddress[subcallAddress];
+ const coveredPcs = _.map(traceForThatSubcall, log => log.pc);
+ traceInfo = {
+ coveredPcs,
+ txHash,
+ address: constants.NEW_CONTRACT,
+ bytecode: data as string,
+ };
+ } else {
+ payload = { method: 'eth_getCode', params: [subcallAddress, BlockParamLiteral.Latest] };
+ jsonRPCResponsePayload = await this.emitPayloadAsync(payload);
+ const runtimeBytecode = jsonRPCResponsePayload.result;
+ const traceForThatSubcall = tracesByContractAddress[subcallAddress];
+ const coveredPcs = _.map(traceForThatSubcall, log => log.pc);
+ traceInfo = {
+ coveredPcs,
+ txHash,
+ address: subcallAddress,
+ runtimeBytecode,
+ };
+ }
+ this._coverageManager.appendTraceInfo(traceInfo);
+ }
} else {
- payload = { method: 'eth_getCode', params: [address, 'latest'] };
- const runtimeBytecode = (await this.emitPayloadAsync(payload)).result;
- const traceInfo: TraceInfoExistingContract = {
- coveredPcs,
- txHash,
- address,
- runtimeBytecode,
- };
- this._coverageManager.appendTraceInfo(traceInfo);
+ for (const subcallAddress of subcallAddresses) {
+ payload = { method: 'eth_getCode', params: [subcallAddress, BlockParamLiteral.Latest] };
+ jsonRPCResponsePayload = await this.emitPayloadAsync(payload);
+ const runtimeBytecode = jsonRPCResponsePayload.result;
+ const traceForThatSubcall = tracesByContractAddress[subcallAddress];
+ const coveredPcs = _.map(traceForThatSubcall, log => log.pc);
+ const traceInfo: TraceInfoExistingContract = {
+ coveredPcs,
+ txHash,
+ address: subcallAddress,
+ runtimeBytecode,
+ };
+ this._coverageManager.appendTraceInfo(traceInfo);
+ }
}
}
private async _recordCallTraceAsync(callData: Partial<CallData>, blockNumber: BlockParam): Promise<void> {
@@ -168,7 +196,7 @@ export class CoverageSubprovider extends Subprovider {
private async _getContractCodeAsync(address: string): Promise<string> {
const payload = {
method: 'eth_getCode',
- params: [address, 'latest'],
+ params: [address, BlockParamLiteral.Latest],
};
const jsonRPCResponsePayload = await this.emitPayloadAsync(payload);
const contractCode: string = jsonRPCResponsePayload.result;
diff --git a/packages/sol-cov/src/index.ts b/packages/sol-cov/src/index.ts
index e5c5e5be3..7a2afbe80 100644
--- a/packages/sol-cov/src/index.ts
+++ b/packages/sol-cov/src/index.ts
@@ -1 +1,5 @@
export { CoverageSubprovider } from './coverage_subprovider';
+export { SolCompilerArtifactAdapter } from './artifact_adapters/sol_compiler_artifact_adapter';
+export { TruffleArtifactAdapter } from './artifact_adapters/truffle_artifact_adapter';
+export { AbstractArtifactAdapter } from './artifact_adapters/abstract_artifact_adapter';
+export { ContractData } from './types';
diff --git a/packages/sol-cov/src/trace.ts b/packages/sol-cov/src/trace.ts
new file mode 100644
index 000000000..cb5410909
--- /dev/null
+++ b/packages/sol-cov/src/trace.ts
@@ -0,0 +1,104 @@
+import { OpCode, StructLog, TransactionTrace } from '@0xproject/types';
+import { addressUtils, BigNumber, logUtils } from '@0xproject/utils';
+import { addHexPrefix, stripHexPrefix } from 'ethereumjs-util';
+import * as fs from 'fs';
+import * as _ from 'lodash';
+
+export interface TraceByContractAddress {
+ [contractAddress: string]: StructLog[];
+}
+
+function getAddressFromStackEntry(stackEntry: string): string {
+ return addressUtils.padZeros(new BigNumber(addHexPrefix(stackEntry)).toString(16));
+}
+
+export function getTracesByContractAddress(structLogs: StructLog[], startAddress: string): TraceByContractAddress {
+ const traceByContractAddress: TraceByContractAddress = {};
+ let currentTraceSegment = [];
+ const callStack = [startAddress];
+ // tslint:disable-next-line:prefer-for-of
+ for (let i = 0; i < structLogs.length; i++) {
+ const structLog = structLogs[i];
+ if (structLog.depth !== callStack.length - 1) {
+ throw new Error("Malformed trace. Trace depth doesn't match call stack depth");
+ }
+ // After that check we have a guarantee that call stack is never empty
+ // If it would: callStack.length - 1 === structLog.depth === -1
+ // That means that we can always safely pop from it
+ currentTraceSegment.push(structLog);
+
+ const isCallLike = _.includes(
+ [OpCode.CallCode, OpCode.StaticCall, OpCode.Call, OpCode.DelegateCall],
+ structLog.op,
+ );
+ const isEndOpcode = _.includes(
+ [OpCode.Return, OpCode.Stop, OpCode.Revert, OpCode.Invalid, OpCode.SelfDestruct],
+ structLog.op,
+ );
+ if (isCallLike) {
+ const currentAddress = _.last(callStack) as string;
+ const jumpAddressOffset = 1;
+ const newAddress = getAddressFromStackEntry(
+ structLog.stack[structLog.stack.length - jumpAddressOffset - 1],
+ );
+ if (structLog === _.last(structLogs)) {
+ throw new Error('Malformed trace. CALL-like opcode can not be the last one');
+ }
+ // Sometimes calls don't change the execution context (current address). When we do a transfer to an
+ // externally owned account - it does the call and immediately returns because there is no fallback
+ // function. We manually check if the call depth had changed to handle that case.
+ const nextStructLog = structLogs[i + 1];
+ if (nextStructLog.depth !== structLog.depth) {
+ callStack.push(newAddress);
+ traceByContractAddress[currentAddress] = (traceByContractAddress[currentAddress] || []).concat(
+ currentTraceSegment,
+ );
+ currentTraceSegment = [];
+ }
+ } else if (isEndOpcode) {
+ const currentAddress = callStack.pop() as string;
+ traceByContractAddress[currentAddress] = (traceByContractAddress[currentAddress] || []).concat(
+ currentTraceSegment,
+ );
+ currentTraceSegment = [];
+ if (structLog.op === OpCode.SelfDestruct) {
+ // After contract execution, we look at all sub-calls to external contracts, and for each one, fetch
+ // the bytecode and compute the coverage for the call. If the contract is destroyed with a call
+ // to `selfdestruct`, we are unable to fetch it's bytecode and compute coverage.
+ // TODO: Refactor this logic to fetch the sub-called contract bytecode before the selfdestruct is called
+ // in order to handle this edge-case.
+ logUtils.warn(
+ "Detected a selfdestruct. Sol-cov currently doesn't support that scenario. We'll just skip the trace part for a destructed contract",
+ );
+ }
+ } else if (structLog.op === OpCode.Create) {
+ // TODO: Extract the new contract address from the stack and handle that scenario
+ logUtils.warn(
+ "Detected a contract created from within another contract. Sol-cov currently doesn't support that scenario. We'll just skip that trace",
+ );
+ return traceByContractAddress;
+ } else {
+ if (structLog !== _.last(structLogs)) {
+ const nextStructLog = structLogs[i + 1];
+ if (nextStructLog.depth === structLog.depth) {
+ continue;
+ } else if (nextStructLog.depth === structLog.depth - 1) {
+ const currentAddress = callStack.pop() as string;
+ traceByContractAddress[currentAddress] = (traceByContractAddress[currentAddress] || []).concat(
+ currentTraceSegment,
+ );
+ currentTraceSegment = [];
+ } else {
+ throw new Error('Malformed trace. Unexpected call depth change');
+ }
+ }
+ }
+ }
+ if (callStack.length !== 0) {
+ throw new Error('Malformed trace. Call stack non empty at the end');
+ }
+ if (currentTraceSegment.length !== 0) {
+ throw new Error('Malformed trace. Current trace segment non empty at the end');
+ }
+ return traceByContractAddress;
+}
diff --git a/packages/sol-cov/src/types.ts b/packages/sol-cov/src/types.ts
index 01359d858..4c3de55a1 100644
--- a/packages/sol-cov/src/types.ts
+++ b/packages/sol-cov/src/types.ts
@@ -98,3 +98,7 @@ export interface TraceInfoExistingContract extends TraceInfoBase {
}
export type TraceInfo = TraceInfoNewContract | TraceInfoExistingContract;
+
+export enum BlockParamLiteral {
+ Latest = 'latest',
+}
diff --git a/packages/sol-cov/test/collect_contracts_data_test.ts b/packages/sol-cov/test/sol_compiler_artifact_adapter_test.ts
index d84ac5a39..0ebad669b 100644
--- a/packages/sol-cov/test/collect_contracts_data_test.ts
+++ b/packages/sol-cov/test/sol_compiler_artifact_adapter_test.ts
@@ -4,16 +4,17 @@ import 'make-promises-safe';
import 'mocha';
import * as path from 'path';
-import { collectContractsData } from '../src/collect_contract_data';
+import { SolCompilerArtifactAdapter } from '../src/artifact_adapters/sol_compiler_artifact_adapter';
const expect = chai.expect;
-describe('Collect contracts data', () => {
+describe('SolCompilerArtifactAdapter', () => {
describe('#collectContractsData', () => {
- it('correctly collects contracts data', () => {
+ it('correctly collects contracts data', async () => {
const artifactsPath = path.resolve(__dirname, 'fixtures/artifacts');
const sourcesPath = path.resolve(__dirname, 'fixtures/contracts');
- const contractsData = collectContractsData(artifactsPath, sourcesPath);
+ const zeroExArtifactsAdapter = new SolCompilerArtifactAdapter(artifactsPath, sourcesPath);
+ const contractsData = await zeroExArtifactsAdapter.collectContractsDataAsync();
_.forEach(contractsData, contractData => {
expect(contractData).to.have.keys([
'sourceCodes',
diff --git a/packages/sol-cov/test/trace_test.ts b/packages/sol-cov/test/trace_test.ts
new file mode 100644
index 000000000..93696b04a
--- /dev/null
+++ b/packages/sol-cov/test/trace_test.ts
@@ -0,0 +1,57 @@
+import { OpCode, StructLog } from '@0xproject/types';
+import * as chai from 'chai';
+import * as fs from 'fs';
+import * as _ from 'lodash';
+import 'mocha';
+import * as path from 'path';
+
+import { getTracesByContractAddress } from '../src/trace';
+
+const expect = chai.expect;
+
+const DEFAULT_STRUCT_LOG: StructLog = {
+ depth: 0,
+ error: '',
+ gas: 0,
+ gasCost: 0,
+ memory: [],
+ op: OpCode.Invalid,
+ pc: 0,
+ stack: [],
+ storage: {},
+};
+
+function addDefaultStructLogFields(compactStructLog: Partial<StructLog> & { op: OpCode; depth: number }): StructLog {
+ return { ...DEFAULT_STRUCT_LOG, ...compactStructLog };
+}
+
+describe('Trace', () => {
+ describe('#getTracesByContractAddress', () => {
+ it('correctly splits trace by contract address', () => {
+ const delegateCallAddress = '0x0000000000000000000000000000000000000002';
+ const trace = [
+ {
+ op: OpCode.DelegateCall,
+ stack: [delegateCallAddress, '0x', '0x', '0x', '0x'],
+ depth: 0,
+ },
+ {
+ op: OpCode.Return,
+ depth: 1,
+ },
+ {
+ op: OpCode.Return,
+ depth: 0,
+ },
+ ];
+ const fullTrace = _.map(trace, compactStructLog => addDefaultStructLogFields(compactStructLog));
+ const startAddress = '0x0000000000000000000000000000000000000001';
+ const traceByContractAddress = getTracesByContractAddress(fullTrace, startAddress);
+ const expectedTraceByContractAddress = {
+ [startAddress]: [fullTrace[0], fullTrace[2]],
+ [delegateCallAddress]: [fullTrace[1]],
+ };
+ expect(traceByContractAddress).to.be.deep.equal(expectedTraceByContractAddress);
+ });
+ });
+});
diff --git a/packages/sol-resolver/CHANGELOG.json b/packages/sol-resolver/CHANGELOG.json
index 44de3825e..895bd2104 100644
--- a/packages/sol-resolver/CHANGELOG.json
+++ b/packages/sol-resolver/CHANGELOG.json
@@ -1,5 +1,18 @@
[
{
+ "version": "0.0.5",
+ "changes": [
+ {
+ "note": "Fix a bug in FsResolver where it tries to read directories as files",
+ "pr": 589
+ },
+ {
+ "note": "Fix a bug in NameResolver where it is not ignoring .sol files",
+ "pr": 589
+ }
+ ]
+ },
+ {
"timestamp": 1527009133,
"version": "0.0.5",
"changes": [
diff --git a/packages/sol-resolver/src/resolvers/fs_resolver.ts b/packages/sol-resolver/src/resolvers/fs_resolver.ts
index 4f05fba88..63fc3448e 100644
--- a/packages/sol-resolver/src/resolvers/fs_resolver.ts
+++ b/packages/sol-resolver/src/resolvers/fs_resolver.ts
@@ -7,7 +7,7 @@ import { Resolver } from './resolver';
export class FSResolver extends Resolver {
// tslint:disable-next-line:prefer-function-over-method
public resolveIfExists(importPath: string): ContractSource | undefined {
- if (fs.existsSync(importPath)) {
+ if (fs.existsSync(importPath) && fs.lstatSync(importPath).isFile()) {
const fileContent = fs.readFileSync(importPath).toString();
return {
source: fileContent,
diff --git a/packages/sol-resolver/src/resolvers/name_resolver.ts b/packages/sol-resolver/src/resolvers/name_resolver.ts
index 76bed802e..e489c70a7 100644
--- a/packages/sol-resolver/src/resolvers/name_resolver.ts
+++ b/packages/sol-resolver/src/resolvers/name_resolver.ts
@@ -6,6 +6,8 @@ import { ContractSource } from '../types';
import { EnumerableResolver } from './enumerable_resolver';
+const SOLIDITY_FILE_EXTENSION = '.sol';
+
export class NameResolver extends EnumerableResolver {
private _contractsDir: string;
constructor(contractsDir: string) {
@@ -13,7 +15,6 @@ export class NameResolver extends EnumerableResolver {
this._contractsDir = contractsDir;
}
public resolveIfExists(lookupContractName: string): ContractSource | undefined {
- const SOLIDITY_FILE_EXTENSION = '.sol';
let contractSource: ContractSource | undefined;
const onFile = (filePath: string) => {
const contractName = path.basename(filePath, SOLIDITY_FILE_EXTENSION);
@@ -32,7 +33,6 @@ export class NameResolver extends EnumerableResolver {
return contractSource;
}
public getAll(): ContractSource[] {
- const SOLIDITY_FILE_EXTENSION = '.sol';
const contractSources: ContractSource[] = [];
const onFile = (filePath: string) => {
const contractName = path.basename(filePath, SOLIDITY_FILE_EXTENSION);
@@ -59,7 +59,12 @@ export class NameResolver extends EnumerableResolver {
const absoluteEntryPath = path.join(dirPath, fileName);
const isDirectory = fs.lstatSync(absoluteEntryPath).isDirectory();
const entryPath = path.relative(this._contractsDir, absoluteEntryPath);
- const isComplete = isDirectory ? this._traverseContractsDir(absoluteEntryPath, onFile) : onFile(entryPath);
+ let isComplete;
+ if (isDirectory) {
+ isComplete = this._traverseContractsDir(absoluteEntryPath, onFile);
+ } else if (fileName.endsWith(SOLIDITY_FILE_EXTENSION)) {
+ isComplete = onFile(entryPath);
+ }
if (isComplete) {
return isComplete;
}
diff --git a/packages/subproviders/src/index.ts b/packages/subproviders/src/index.ts
index ff28b8a8d..6cc650a4d 100644
--- a/packages/subproviders/src/index.ts
+++ b/packages/subproviders/src/index.ts
@@ -4,6 +4,7 @@ export { ECSignature } from '@0xproject/types';
import { LedgerEthereumClient } from './types';
+export { prependSubprovider } from './utils/subprovider_utils';
export { EmptyWalletSubprovider } from './subproviders/empty_wallet_subprovider';
export { FakeGasEstimateSubprovider } from './subproviders/fake_gas_estimate_subprovider';
export { InjectedWeb3Subprovider } from './subproviders/injected_web3';
diff --git a/packages/subproviders/src/utils/subprovider_utils.ts b/packages/subproviders/src/utils/subprovider_utils.ts
new file mode 100644
index 000000000..24ebedd06
--- /dev/null
+++ b/packages/subproviders/src/utils/subprovider_utils.ts
@@ -0,0 +1,15 @@
+import ProviderEngine = require('web3-provider-engine');
+
+import { Subprovider } from '../subproviders/subprovider';
+
+/**
+ * Prepends a subprovider to a provider
+ * @param provider Given provider
+ * @param subprovider Subprovider to prepend
+ */
+export function prependSubprovider(provider: ProviderEngine, subprovider: Subprovider): void {
+ subprovider.setEngine(provider);
+ // HACK: We use implementation details of provider engine here
+ // https://github.com/MetaMask/provider-engine/blob/master/index.js#L68
+ (provider as any)._providers = [subprovider, ...(provider as any)._providers];
+}
diff --git a/packages/types/CHANGELOG.json b/packages/types/CHANGELOG.json
index 23325fedc..8abc5bd99 100644
--- a/packages/types/CHANGELOG.json
+++ b/packages/types/CHANGELOG.json
@@ -3,6 +3,10 @@
"version": "0.7.0",
"changes": [
{
+ "note": "Make OpCode type an enum",
+ "pr": 589
+ },
+ {
"note":
"Moved ExchangeContractErrs, DoneCallback, Token, OrderRelevantState, OrderStateValid, OrderStateInvalid, OrderState, OrderAddresses and OrderValues types from 0x.js",
"pr": 579
diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts
index f28c2f9a3..055c47e0a 100644
--- a/packages/types/src/index.ts
+++ b/packages/types/src/index.ts
@@ -58,7 +58,18 @@ export interface DataItem {
components?: DataItem[];
}
-export type OpCode = string;
+export enum OpCode {
+ DelegateCall = 'DELEGATECALL',
+ Revert = 'REVERT',
+ Create = 'CREATE',
+ Stop = 'STOP',
+ Invalid = 'INVALID',
+ CallCode = 'CALLCODE',
+ StaticCall = 'STATICCALL',
+ Return = 'RETURN',
+ Call = 'CALL',
+ SelfDestruct = 'SELFDESTRUCT',
+}
export interface StructLog {
depth: number;
diff --git a/packages/typescript-typings/types/web3-provider-engine/index.d.ts b/packages/typescript-typings/types/web3-provider-engine/index.d.ts
index 15a8d0005..8d5aef749 100644
--- a/packages/typescript-typings/types/web3-provider-engine/index.d.ts
+++ b/packages/typescript-typings/types/web3-provider-engine/index.d.ts
@@ -1,8 +1,12 @@
declare module 'web3-provider-engine' {
- class Web3ProviderEngine {
+ import { Provider, JSONRPCRequestPayload, JSONRPCResponsePayload } from '@0xproject/types';
+ class Web3ProviderEngine implements Provider {
public on(event: string, handler: () => void): void;
- public send(payload: any): void;
- public sendAsync(payload: any, callback: (error: any, response: any) => void): void;
+ public send(payload: JSONRPCRequestPayload): void;
+ public sendAsync(
+ payload: JSONRPCRequestPayload,
+ callback: (error: null | Error, response: JSONRPCResponsePayload) => void,
+ ): void;
public addProvider(provider: any): void;
public start(): void;
public stop(): void;
@@ -19,13 +23,13 @@ declare module 'web3-provider-engine/subproviders/subprovider' {
export = Subprovider;
}
declare module 'web3-provider-engine/subproviders/rpc' {
- import { JSONRPCRequestPayload } from '@0xproject/types';
+ import { JSONRPCRequestPayload, JSONRPCResponsePayload } from '@0xproject/types';
class RpcSubprovider {
constructor(options: { rpcUrl: string });
public handleRequest(
payload: JSONRPCRequestPayload,
next: () => void,
- end: (err: Error | null, data?: any) => void,
+ end: (err: Error | null, data?: JSONRPCResponsePayload) => void,
): void;
}
export = RpcSubprovider;
@@ -37,13 +41,13 @@ declare module 'web3-provider-engine/util/rpc-cache-utils' {
export = ProviderEngineRpcUtils;
}
declare module 'web3-provider-engine/subproviders/fixture' {
- import { JSONRPCRequestPayload } from '@0xproject/types';
+ import { JSONRPCRequestPayload, JSONRPCResponsePayload } from '@0xproject/types';
class FixtureSubprovider {
constructor(staticResponses: any);
public handleRequest(
payload: JSONRPCRequestPayload,
next: () => void,
- end: (err: Error | null, data?: any) => void,
+ end: (err: Error | null, data?: JSONRPCResponsePayload) => void,
): void;
}
export = FixtureSubprovider;
diff --git a/packages/utils/CHANGELOG.json b/packages/utils/CHANGELOG.json
index 853acae55..616a17d62 100644
--- a/packages/utils/CHANGELOG.json
+++ b/packages/utils/CHANGELOG.json
@@ -9,6 +9,15 @@
]
},
{
+ "version": "0.7.0",
+ "changes": [
+ {
+ "note": "Add logUtils.warn",
+ "pr": 589
+ }
+ ]
+ },
+ {
"timestamp": 1525477860,
"version": "0.6.1",
"changes": [
diff --git a/packages/utils/package.json b/packages/utils/package.json
index 99d3d9256..24551dd93 100644
--- a/packages/utils/package.json
+++ b/packages/utils/package.json
@@ -38,6 +38,7 @@
"@0xproject/types": "^0.7.0",
"@0xproject/typescript-typings": "^0.3.2",
"@types/node": "^8.0.53",
+ "ethereumjs-util": "^5.1.1",
"bignumber.js": "~4.1.0",
"ethers": "^3.0.15",
"js-sha3": "^0.7.0",
diff --git a/packages/utils/src/abi_decoder.ts b/packages/utils/src/abi_decoder.ts
index c78bfa343..d2d8364ca 100644
--- a/packages/utils/src/abi_decoder.ts
+++ b/packages/utils/src/abi_decoder.ts
@@ -12,21 +12,12 @@ import {
import * as ethers from 'ethers';
import * as _ from 'lodash';
+import { addressUtils } from './address_utils';
import { BigNumber } from './configured_bignumber';
export class AbiDecoder {
private _savedABIs: AbiDefinition[] = [];
private _methodIds: { [signatureHash: string]: EventAbi } = {};
- private static _padZeros(address: string): string {
- let formatted = address;
- if (_.startsWith(formatted, '0x')) {
- formatted = formatted.slice(2);
- }
-
- const addressLength = 40;
- formatted = _.padStart(formatted, addressLength, '0');
- return `0x${formatted}`;
- }
constructor(abiArrays: AbiDefinition[][]) {
_.forEach(abiArrays, this.addABI.bind(this));
}
@@ -56,7 +47,7 @@ export class AbiDecoder {
}
if (param.type === SolidityTypes.Address) {
const baseHex = 16;
- value = AbiDecoder._padZeros(new BigNumber(value).toString(baseHex));
+ value = addressUtils.padZeros(new BigNumber(value).toString(baseHex));
} else if (param.type === SolidityTypes.Uint256 || param.type === SolidityTypes.Uint) {
value = new BigNumber(value);
} else if (param.type === SolidityTypes.Uint8) {
diff --git a/packages/utils/src/address_utils.ts b/packages/utils/src/address_utils.ts
index e25bde249..cc43bd477 100644
--- a/packages/utils/src/address_utils.ts
+++ b/packages/utils/src/address_utils.ts
@@ -1,4 +1,6 @@
+import { addHexPrefix, stripHexPrefix } from 'ethereumjs-util';
import * as jsSHA3 from 'js-sha3';
+import * as _ from 'lodash';
const BASIC_ADDRESS_REGEX = /^(0x)?[0-9a-f]{40}$/i;
const SAME_CASE_ADDRESS_REGEX = /^(0x)?([0-9a-f]{40}|[0-9A-F]{40})$/;
@@ -38,4 +40,7 @@ export const addressUtils = {
return isValidChecksummedAddress;
}
},
+ padZeros(address: string): string {
+ return addHexPrefix(_.padStart(stripHexPrefix(address), 40, '0'));
+ },
};
diff --git a/packages/utils/src/log_utils.ts b/packages/utils/src/log_utils.ts
index d0f0e34c9..87f8479b5 100644
--- a/packages/utils/src/log_utils.ts
+++ b/packages/utils/src/log_utils.ts
@@ -2,4 +2,7 @@ export const logUtils = {
log(...args: any[]): void {
console.log(...args); // tslint:disable-line:no-console
},
+ warn(...args: any[]): void {
+ console.warn(...args); // tslint:disable-line:no-console
+ },
};