aboutsummaryrefslogtreecommitdiffstats
path: root/packages/sol-tracing-utils/src/artifact_adapters
diff options
context:
space:
mode:
Diffstat (limited to 'packages/sol-tracing-utils/src/artifact_adapters')
-rw-r--r--packages/sol-tracing-utils/src/artifact_adapters/abstract_artifact_adapter.ts5
-rw-r--r--packages/sol-tracing-utils/src/artifact_adapters/sol_compiler_artifact_adapter.ts61
-rw-r--r--packages/sol-tracing-utils/src/artifact_adapters/truffle_artifact_adapter.ts88
3 files changed, 154 insertions, 0 deletions
diff --git a/packages/sol-tracing-utils/src/artifact_adapters/abstract_artifact_adapter.ts b/packages/sol-tracing-utils/src/artifact_adapters/abstract_artifact_adapter.ts
new file mode 100644
index 000000000..fcc6562ad
--- /dev/null
+++ b/packages/sol-tracing-utils/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-tracing-utils/src/artifact_adapters/sol_compiler_artifact_adapter.ts b/packages/sol-tracing-utils/src/artifact_adapters/sol_compiler_artifact_adapter.ts
new file mode 100644
index 000000000..57391abbe
--- /dev/null
+++ b/packages/sol-tracing-utils/src/artifact_adapters/sol_compiler_artifact_adapter.ts
@@ -0,0 +1,61 @@
+import { logUtils } from '@0x/utils';
+import { CompilerOptions, ContractArtifact } from 'ethereum-types';
+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 readonly _artifactsPath: string;
+ private readonly _sourcesPath: string;
+ /**
+ * Instantiates a SolCompilerArtifactAdapter
+ * @param artifactsPath Path to your artifacts directory
+ * @param sourcesPath Path to your contract sources directory
+ */
+ constructor(artifactsPath?: string, sourcesPath?: string) {
+ super();
+ const config: CompilerOptions = fs.existsSync(CONFIG_FILE)
+ ? JSON.parse(fs.readFileSync(CONFIG_FILE).toString())
+ : {};
+ if (_.isUndefined(artifactsPath) && _.isUndefined(config.artifactsDir)) {
+ throw new Error(`artifactsDir not found in ${CONFIG_FILE}`);
+ }
+ this._artifactsPath = (artifactsPath || config.artifactsDir) as string;
+ if (_.isUndefined(sourcesPath) && _.isUndefined(config.contractsDir)) {
+ throw new Error(`contractsDir not found in ${CONFIG_FILE}`);
+ }
+ this._sourcesPath = (sourcesPath || config.contractsDir) as string;
+ }
+ 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: ContractArtifact = JSON.parse(fs.readFileSync(artifactFileName).toString());
+ if (_.isUndefined(artifact.compilerOutput.evm)) {
+ logUtils.warn(`${artifactFileName} doesn't contain bytecode. Skipping...`);
+ continue;
+ }
+ let sources = _.keys(artifact.sources);
+ sources = _.map(sources, relativeFilePath => path.resolve(this._sourcesPath, relativeFilePath));
+ 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-tracing-utils/src/artifact_adapters/truffle_artifact_adapter.ts b/packages/sol-tracing-utils/src/artifact_adapters/truffle_artifact_adapter.ts
new file mode 100644
index 000000000..bb2b15153
--- /dev/null
+++ b/packages/sol-tracing-utils/src/artifact_adapters/truffle_artifact_adapter.ts
@@ -0,0 +1,88 @@
+import { Compiler, CompilerOptions } from '@0x/sol-compiler';
+import * as fs from 'fs';
+import * as glob from 'glob';
+import * as path from 'path';
+
+import { ContractData } from '../types';
+
+import { AbstractArtifactAdapter } from './abstract_artifact_adapter';
+import { SolCompilerArtifactAdapter } from './sol_compiler_artifact_adapter';
+
+const DEFAULT_TRUFFLE_ARTIFACTS_DIR = './build/contracts';
+
+interface TruffleConfig {
+ solc?: any;
+ contracts_build_directory?: string;
+}
+
+export class TruffleArtifactAdapter extends AbstractArtifactAdapter {
+ private readonly _solcVersion: string;
+ private readonly _projectRoot: string;
+ /**
+ * Instantiates a TruffleArtifactAdapter
+ * @param projectRoot Path to the truffle project's root directory
+ * @param solcVersion Solidity version with which to compile all the contracts
+ */
+ constructor(projectRoot: string, solcVersion: string) {
+ super();
+ this._solcVersion = solcVersion;
+ this._projectRoot = projectRoot;
+ }
+ public async collectContractsDataAsync(): Promise<ContractData[]> {
+ const artifactsDir = '.0x-artifacts';
+ const contractsDir = path.join(this._projectRoot, 'contracts');
+ const truffleConfig = this._getTruffleConfig();
+ const solcConfig = truffleConfig.solc || {};
+ const truffleArtifactsDirectory = truffleConfig.contracts_build_directory || DEFAULT_TRUFFLE_ARTIFACTS_DIR;
+ this._assertSolidityVersionIsCorrect(truffleArtifactsDirectory);
+ const compilerOptions: CompilerOptions = {
+ contractsDir,
+ artifactsDir,
+ compilerSettings: {
+ ...solcConfig,
+ 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, contractsDir);
+ const contractsDataFrom0xArtifacts = await solCompilerArtifactAdapter.collectContractsDataAsync();
+ return contractsDataFrom0xArtifacts;
+ }
+ private _getTruffleConfig(): TruffleConfig {
+ const truffleConfigFileShort = path.resolve(path.join(this._projectRoot, 'truffle.js'));
+ const truffleConfigFileLong = path.resolve(path.join(this._projectRoot, 'truffle-config.js'));
+ if (fs.existsSync(truffleConfigFileShort)) {
+ const truffleConfig = require(truffleConfigFileShort);
+ return truffleConfig;
+ } else if (fs.existsSync(truffleConfigFileLong)) {
+ const truffleConfig = require(truffleConfigFileLong);
+ return truffleConfig;
+ } else {
+ throw new Error(
+ `Neither ${truffleConfigFileShort} nor ${truffleConfigFileLong} exists. Make sure the project root is correct`,
+ );
+ }
+ }
+ private _assertSolidityVersionIsCorrect(truffleArtifactsDirectory: string): void {
+ const artifactsGlob = `${truffleArtifactsDirectory}/**/*.json`;
+ const artifactFileNames = glob.sync(artifactsGlob, { absolute: true });
+ for (const artifactFileName of artifactFileNames) {
+ const artifact = JSON.parse(fs.readFileSync(artifactFileName).toString());
+ const compilerVersion = artifact.compiler.version;
+ if (!compilerVersion.startsWith(this._solcVersion)) {
+ throw new Error(
+ `${artifact.contractName} was compiled with solidity ${compilerVersion} but specified version is ${
+ this._solcVersion
+ } making it impossible to process traces`,
+ );
+ }
+ }
+ }
+}