Skip to content
Open
Show file tree
Hide file tree
Changes from 3 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