Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@ $ tronbox compile

To compile all contracts, use the `--compile-all` option.

To compile an specific set of contracts:

```bash
tronbox compile contracts/your_contract.sol contracts/another_contract.sol ...
```

Specify a network using the `--network` option. Network name must exist in the configuration. For details, see [Compile a Project](https://tronbox.io/docs/guides/compile-contracts).

### Migrate
Expand Down
36 changes: 36 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
"graphlib": "2.1.8",
"homedir": "0.6.0",
"lodash": "4.17.23",
"md5": "^2.3.0",
"mkdirp": "0.5.6",
"mocha": "11.7.4",
"node-dir": "0.1.17",
Expand Down
41 changes: 35 additions & 6 deletions src/components/Compile/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ const compile = function (sources, options, callback) {
replacement = '/' + replacement;
replacement = replacement.replace(':', '');
}
//Convert absolute paths to relative for reproducible builds
replacement = makeRelative(replacement, options);

// Save the result
operatingSystemIndependentSources[replacement] = sources[source];
Expand All @@ -69,14 +71,19 @@ const compile = function (sources, options, callback) {
...settings,
outputSelection: {
'*': {
'': ['legacyAST', 'ast'],
'': ['ast'],
'*': [
'abi',
'devdoc',
'userdoc',
'metadata',
'storageLayout',
'evm.bytecode.object',
'evm.bytecode.sourceMap',
'evm.bytecode.linkReferences',
'evm.deployedBytecode.object',
'evm.deployedBytecode.sourceMap'
'evm.deployedBytecode.sourceMap',
'evm.methodIdentifiers',
]
}
}
Expand All @@ -85,7 +92,7 @@ const compile = function (sources, options, callback) {

// Nothing to compile? Bail.
if (!Object.keys(sources).length) {
return callback(null, [], []);
return callback(null, [], [], {});
}

Object.keys(operatingSystemIndependentSources).forEach(function (file_path) {
Expand Down Expand Up @@ -158,9 +165,9 @@ const compile = function (sources, options, callback) {
source: operatingSystemIndependentSources[source_path],
sourceMap: contract.evm.bytecode.sourceMap,
deployedSourceMap: contract.evm.deployedBytecode.sourceMap,
legacyAST: standardOutput.sources[source_path].legacyAST,
ast: standardOutput.sources[source_path].ast,
abi: contract.abi,
metadata: contract.metadata,
bytecode: '0x' + contract.evm.bytecode.object,
deployedBytecode: '0x' + contract.evm.deployedBytecode.object,
unlinked_binary: '0x' + contract.evm.bytecode.object, // deprecated
Expand Down Expand Up @@ -217,7 +224,7 @@ const compile = function (sources, options, callback) {
});
});

callback(null, returnVal, files);
callback(null, returnVal, files, solcStandardInput);
};

function replaceLinkReferences(bytecode, linkReferences, libraryName) {
Expand All @@ -237,6 +244,21 @@ function replaceLinkReferences(bytecode, linkReferences, libraryName) {
return bytecode;
}

//Takes an absolute path and return a relative path to ensure reproducibility
const makeRelative = (contractPath, options) => {
const absolutePath = contractPath

const projectRoot = path.resolve(options.working_directory);
// Normalize for comparison (important on Windows)
const normalizedAbsolute = path.resolve(absolutePath);
const normalizedRoot = path.resolve(projectRoot);

// Convert to project-relative path
let relativePath = path.relative(normalizedRoot, normalizedAbsolute);

return relativePath;
};

function orderABI(contract) {
const { abi, contractName, ast } = contract;

Expand Down Expand Up @@ -289,6 +311,13 @@ compile.all = function (options, callback) {
});
};

//Compile an specific set of contracts or a single one
compile.specific = function (options, callback) {

options.paths = options.compileTargets;
compile.with_dependencies(options, callback);

};
// contracts_directory: String. Directory where .sol files can be found.
// build_directory: String. Optional. Directory where .sol.js files can be found. Only required if `all` is false.
// all: Boolean. Compile all sources found. Defaults to true. If false, will compare sources against built files
Expand All @@ -300,7 +329,7 @@ compile.necessary = function (options, callback) {
if (err) return callback(err);

if (updated.length === 0) {
return callback(null, [], {});
return callback(null, [], {}, {});
}

options.paths = updated;
Expand Down
3 changes: 3 additions & 0 deletions src/components/Config.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ function Config() {
return path.resolve(self.working_directory, value);
}
},
build_info_directory: function () {
return path.join(self.working_directory, 'build-info');
},
contracts_directory: {
default: function () {
return path.join(self.working_directory, 'contracts');
Expand Down
20 changes: 7 additions & 13 deletions src/components/ContractSchema/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const pkgVersion = '2.0.1';
const pkgVersion = '2.0.2';
const Ajv = require('ajv');

const contractObjectSchema = require('./spec/contract-object.spec.json');
Expand Down Expand Up @@ -62,6 +62,12 @@ const properties = {
return value;
}
},
metadata: {
sources: ['metadata'],
transform(value) {
return typeof value == 'string' ? value : undefined;
}
},
sourceMap: {
sources: ['sourceMap', 'srcmap', 'evm.bytecode.sourceMap']
},
Expand All @@ -71,18 +77,6 @@ const properties = {
source: {},
sourcePath: {},
ast: {},
legacyAST: {
transform: function (value, obj) {
const schemaVersion = obj.schemaVersion || '0.0.0';

// legacyAST introduced in v2.0.0
if (schemaVersion[0] < 2) {
return obj.ast;
} else {
return value;
}
}
},
compiler: {},
networks: {
transform: function (value) {
Expand Down
10 changes: 4 additions & 6 deletions src/components/ContractSchema/spec/contract-object.spec.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@
}
]
},
"metadata": {
"type": "string",
"description": "Solidity compiler metadata JSON"
},
"sourceMap": {
"allOf": [
{
Expand Down Expand Up @@ -75,9 +79,6 @@
"ast": {
"$ref": "#/definitions/AST"
},
"legacyAST": {
"$ref": "#/definitions/LegacyAST"
},
"compiler": {
"type": "object",
"properties": {
Expand Down Expand Up @@ -151,9 +152,6 @@
"AST": {
"type": "object"
},
"LegacyAST": {
"type": "object"
},
"SchemaVersion": {
"type": "string",
"pattern": "[0-9]+\\.[0-9]+\\.[0-9]+"
Expand Down
58 changes: 49 additions & 9 deletions src/components/WorkflowCompile.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ const { expect } = require('../lib/utils');
const Resolver = require('./Resolver');
const Artifactor = require('./Artifactor');
const TronWrap = require('./TronWrap');
const fs = require("fs");
const md5 = require('md5');

async function getCompilerVersion(options) {
const config = Config.detect(options);
Expand Down Expand Up @@ -40,7 +42,7 @@ const Contracts = {
const self = this;

expect.options(options, ['contracts_build_directory']);

expect.options(options, ['build_info_directory']);
expect.one(options, ['contracts_directory', 'files']);

// Use a config object to ensure we get the default sources.
Expand All @@ -54,34 +56,51 @@ const Contracts = {
config.artifactor = new Artifactor(config.contracts_build_directory);
}

function finished(err, contracts, paths) {
// Normalize compile targets
if (Array.isArray(config.compileTargets) && config.compileTargets.length > 0) {
config.compileTargets = config.compileTargets.map(p =>
path.resolve(config.working_directory, p)
);
}

function finished(err, contracts, paths, solcStandardInput) {
if (err) return callback(err);

if (contracts != null && Object.keys(contracts).length > 0) {
// Create a hash of the standard JSON input to use as a unique identifier for this compilation.
const inputFileName = md5(JSON.stringify(solcStandardInput));
// Write contract artifacts
self.write_contracts(contracts, config, async function (err, abstractions) {
options.logger.log('');
options.logger.log(`> Compiled successfully using:`);
const solcVersion = options.networks?.compilers
? options.networks?.compilers?.solc?.version
: options.compilers?.solc?.version;
options.logger.log(` - solc${options.evm ? '(EVM)' : ''}: ${solcVersion}`);
callback(err, abstractions, paths);
callback(err, abstractions, paths, solcStandardInput);
});
self.write_buildInfo(solcStandardInput, config, inputFileName)
} else {
options.logger.log('> Everything is up to date, there is nothing to compile.');
callback(null, [], paths);
callback(null, [], paths, solcStandardInput);
}
}

function start() {
options.logger.log('Compiling your contracts...');
options.logger.log('===========================');

// Compile specific contracts
if (config.compileTargets && config.compileTargets.length > 0) {
return compile.specific(config, finished);
}

//If ALL option is selected compile all contracts
if (config.all === true || config.compileAll === true) {
compile.all(config, finished);
} else {
compile.necessary(config, finished);
return compile.all(config, finished);
}
//Compile modified contracts if none of the above is true
return compile.necessary(config, finished);
}

getCompilerVersion(options)
Expand All @@ -102,8 +121,8 @@ const Contracts = {
if (!options.quietWrite) {
options.logger.log(
'Writing artifacts to .' +
path.sep +
path.relative(options.working_directory, options.contracts_build_directory)
path.sep +
path.relative(options.working_directory, options.contracts_build_directory)
);
}

Expand All @@ -118,7 +137,28 @@ const Contracts = {
})
.catch(callback);
});
},
//Write the standard JSON input to a file in the build info directory. This can be used for verification or debugging purposes.
write_buildInfo: function (solcStandardInput, options, inputFileName) {

mkdirp(options.build_info_directory, function (err) {
if (err != null) {
callback(err);
return;
}

if (!options.quietWrite) {
options.logger.log(
'Writing jsnoninput file to .' +
path.sep +
path.relative(options.working_directory, options.build_info_directory)
);
}
fs.writeFileSync(path.relative(options.working_directory, options.build_info_directory) + path.sep + `${inputFileName}.json`, JSON.stringify(solcStandardInput));

})
}

};

module.exports = Contracts;
Loading