Skip to content

Commit 83499b5

Browse files
authored
Merge pull request #323 from tronprotocol/release/4.6.0
Release/4.6.0
2 parents ead5d1b + fc2f7fc commit 83499b5

45 files changed

Lines changed: 1783 additions & 3190 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CHANGELOG.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,34 @@
1+
**4.6.0**
2+
3+
### Features
4+
5+
- Enhanced `flatten` command
6+
- Unified SPDX license header generation across all input files
7+
- Unified `pragma abicoder` handling and normalization
8+
- Added dependency library version information in build output
9+
10+
### Breaking Changes
11+
12+
- **BREAKING CHANGE**: Removed EPM (Ethereum Package Manager) support
13+
- **BREAKING CHANGE**: Configuration directory paths (`build_directory`, `contracts_directory`, `contracts_build_directory`, `migrations_directory`, `test_directory`) are now constrained to the project root
14+
- **BREAKING CHANGE**: Disallowed running and importing files outside the project directory
15+
- **BREAKING CHANGE**: Removed global config injection
16+
17+
### Bug Fixes & Improvements
18+
19+
- Added checksum validation for downloaded soljson compiler files
20+
- Improved error capturing and unhandled promise rejection handling
21+
- Normalized error output formatting and added explicit exit codes
22+
- Enhanced runtime stability with null-safety checks on deployment and contract interactions
23+
24+
### Dependencies
25+
26+
- Upgraded `tronweb` from 6.1.1 to 6.2.2
27+
- Upgraded `axios` from 1.12.0 to 1.13.6
28+
- Upgraded `glob` to 13.0.6
29+
- Upgraded `ajv` to 6.14.0
30+
- Upgraded `yauzl` to 3.2.1
31+
132
**4.5.0**
233

334
### Major Refactoring

package-lock.json

Lines changed: 907 additions & 813 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "tronbox",
33
"namespace": "tronprotocol",
4-
"version": "4.5.0",
4+
"version": "4.6.0",
55
"description": "TronBox - Simple development framework for Tron",
66
"keywords": [
77
"TronBox",
@@ -19,9 +19,9 @@
1919
},
2020
"dependencies": {
2121
"@solidity-parser/parser": "0.20.2",
22-
"ajv": "6.12.6",
22+
"ajv": "6.14.0",
2323
"async": "2.6.4",
24-
"axios": "1.12.0",
24+
"axios": "1.13.6",
2525
"bignumber.js": "7.2.1",
2626
"chai": "4.1.2",
2727
"chalk": "2.4.2",
@@ -31,7 +31,7 @@
3131
"ethers": "6.15.0",
3232
"find-up": "4.1.0",
3333
"fs-extra": "8.1.0",
34-
"glob": "11.1.0",
34+
"glob": "13.0.6",
3535
"graphlib": "2.1.8",
3636
"homedir": "0.6.0",
3737
"lodash": "4.17.23",
@@ -42,11 +42,10 @@
4242
"solc": "0.8.25",
4343
"source-map-support": "0.5.21",
4444
"tmp": "0.0.33",
45-
"tronweb": "6.1.1",
46-
"tsort": "0.0.1",
45+
"tronweb": "6.2.2",
4746
"vcsurl": "0.1.1",
4847
"yargs": "15.4.1",
49-
"yauzl": "3.2.0"
48+
"yauzl": "3.2.1"
5049
},
5150
"devDependencies": {
5251
"@babel/cli": "7.28.3",
@@ -59,6 +58,11 @@
5958
"prettier": "2.8.8",
6059
"tslib": "2.8.1"
6160
},
61+
"overrides": {
62+
"mocha": {
63+
"serialize-javascript": "7.0.3"
64+
}
65+
},
6266
"bin": {
6367
"tronbox": "build/tronbox.js"
6468
},

sample-projects/javascript-metacoin/contracts/MetaCoin.sol

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ contract MetaCoin is ERC20 {
2020
// Unlock time for TRX locking feature
2121
uint256 public unlockTime;
2222

23+
// Tracks whether lock() has ever been called
24+
bool public isLocked;
25+
2326
/**
2427
* @param _initialSupply The initial supply.
2528
*/
@@ -51,7 +54,12 @@ contract MetaCoin is ERC20 {
5154
require(block.timestamp < _unlockTime, 'Unlock time should be in the future');
5255
require(msg.sender == owner, "You aren't the owner");
5356

57+
if (isLocked) {
58+
require(_unlockTime >= unlockTime, 'Unlock time can only be extended');
59+
}
60+
5461
unlockTime = _unlockTime;
62+
isLocked = true;
5563
}
5664

5765
/**
@@ -62,8 +70,11 @@ contract MetaCoin is ERC20 {
6270
require(block.timestamp >= unlockTime, "You can't withdraw yet");
6371
require(msg.sender == owner, "You aren't the owner");
6472
require(_to != address(0), 'Invalid address');
73+
require(isLocked, 'Funds are not locked yet');
6574

66-
payable(_to).transfer(address(this).balance);
75+
isLocked = false;
76+
(bool success, ) = payable(_to).call{ value: address(this).balance }('');
77+
require(success, 'Transfer failed');
6778
}
6879

6980
/**

src/components/Artifactor.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,13 @@ Artifactor.prototype.save = function (object, options) {
2626
let output_path = object.contractName;
2727

2828
// Create new path off of destination.
29-
output_path = path.join(self.destination, output_path);
29+
const destinationPath = path.resolve(self.destination);
30+
output_path = path.join(destinationPath, output_path);
3031
output_path = path.resolve(output_path);
32+
const relative = path.relative(destinationPath, output_path);
33+
if (relative.startsWith('..') || path.isAbsolute(relative)) {
34+
return reject(new Error(`Invalid contractName "${object.contractName}"`));
35+
}
3136

3237
// Add json extension.
3338
output_path = output_path + '.json';
@@ -43,7 +48,7 @@ Artifactor.prototype.save = function (object, options) {
4348
try {
4449
existingObjDirty = JSON.parse(json);
4550
} catch (e) {
46-
reject(e);
51+
return reject(e);
4752
}
4853

4954
// normalize existing and merge into final

src/components/Box/lib/utils/download.js

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ const axios = require('axios');
1616
const path = require('path');
1717
const fs = require('fs-extra');
1818
const util = require('util');
19+
const crypto = require('crypto');
1920

2021
const cwd = process.cwd();
2122

@@ -76,7 +77,7 @@ GithubDownloader.prototype.start = function () {
7677
.catch(err => _this.emit('error', err));
7778
});
7879
} else {
79-
_this.emit('Error', new Error(JSON.stringify(item, null, 2) + '\n does not have type.'));
80+
_this.emit('error', new Error(JSON.stringify(item, null, 2) + '\n does not have type.'));
8081
}
8182
}
8283

@@ -152,6 +153,15 @@ function extractZip(zipFile, outputDir, callback) {
152153
if (err) return _this.emit('error', err);
153154

154155
const file = path.resolve(outputDir, entry.fileName);
156+
const normalizedOutputDir = path.resolve(outputDir);
157+
const relative = path.relative(normalizedOutputDir, file);
158+
if (relative.startsWith('..') || path.isAbsolute(relative)) {
159+
return _this.emit(
160+
'error',
161+
new Error(`Refusing to extract unsafe zip entry outside destination: ${entry.fileName}`)
162+
);
163+
}
164+
155165
fs.ensureDir(path.dirname(file), err => {
156166
if (err) return _this.emit('error', err);
157167

@@ -188,7 +198,7 @@ function downloadZip() {
188198
_this._getZip = true;
189199

190200
_this._log.forEach(function (file) {
191-
fs.remove(file);
201+
fs.removeSync(file);
192202
});
193203

194204
const tmpdir = generateTempDir();
@@ -221,5 +231,5 @@ function downloadZip() {
221231
}
222232

223233
function generateTempDir() {
224-
return path.join(cwd, Date.now().toString() + '-' + Math.random().toString().substring(2));
234+
return path.join(cwd, Date.now().toString() + '-' + crypto.randomBytes(16).toString('hex'));
225235
}

src/components/Box/lib/utils/index.js

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,22 @@ module.exports = {
1515
.then(function () {
1616
return unbox.setupTempDirectory();
1717
})
18-
.then(function (dir, func) {
18+
.then(function ({ dir, cleanupCallback }) {
1919
// save tmpDir result
2020
tmpDir = dir;
21-
tmpCleanup = func;
21+
tmpCleanup = cleanupCallback;
2222
})
2323
.then(function () {
2424
return unbox.fetchRepository(url, tmpDir);
2525
})
2626
.then(function () {
2727
return unbox.copyTempIntoDestination(tmpDir, destination);
2828
})
29-
.then(tmpCleanup);
29+
.then(tmpCleanup)
30+
.catch(error => {
31+
if (tmpCleanup) tmpCleanup();
32+
throw error;
33+
});
3034
},
3135

3236
unpackBox: function (destination) {

src/components/Box/lib/utils/unbox.js

Lines changed: 33 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ const path = require('path');
33
const axios = require('axios');
44
const vcsurl = require('vcsurl');
55
const tmp = require('tmp');
6-
const exec = require('child_process').exec;
6+
const { spawnSync } = require('child_process');
77
const ghdownload = require('./download');
88
const cwd = process.cwd();
99

@@ -59,7 +59,7 @@ function setupTempDirectory() {
5959
tmp.dir({ dir: cwd, unsafeCleanup: true }, function (err, dir, cleanupCallback) {
6060
if (err) return reject(err);
6161

62-
accept(path.join(dir, 'box'), cleanupCallback);
62+
accept({ dir: path.join(dir, 'box'), cleanupCallback });
6363
});
6464
});
6565
}
@@ -68,7 +68,7 @@ function fetchRepository(url, dir) {
6868
return new Promise(function (accept, reject) {
6969
// Download the package from github.
7070
ghdownload(url, dir)
71-
.on('err', function (err) {
71+
.on('error', function (err) {
7272
reject(err);
7373
})
7474
.on('end', function () {
@@ -98,18 +98,26 @@ function readBoxConfig(destination) {
9898

9999
function cleanupUnpack(boxConfig, destination) {
100100
const needingRemoval = boxConfig.ignore || [];
101+
const workingDirectoryPath = path.resolve(destination);
101102

102103
// remove box config file
103104
needingRemoval.push('tronbox.json');
104105
needingRemoval.push('tronbox-init.json');
106+
needingRemoval.push('post-unpack.sh');
105107

106108
const promises = needingRemoval
107109
.map(function (file_path) {
108110
return path.join(destination, file_path);
109111
})
110112
.map(function (file_path) {
111113
return new Promise(function (accept, reject) {
112-
fs.remove(file_path, function (err) {
114+
const resolvedPath = path.resolve(workingDirectoryPath, file_path);
115+
const relative = path.relative(workingDirectoryPath, resolvedPath);
116+
if (relative.startsWith('..') || path.isAbsolute(relative)) {
117+
return accept();
118+
}
119+
120+
fs.remove(resolvedPath, function (err) {
113121
if (err) return reject(err);
114122
accept();
115123
});
@@ -119,28 +127,33 @@ function cleanupUnpack(boxConfig, destination) {
119127
return Promise.all(promises);
120128
}
121129

122-
function installBoxDependencies(boxConfig, destination) {
123-
const postUnpack = boxConfig.hooks['post-unpack'];
124-
130+
function installBoxDependencies(_boxConfig, destination) {
125131
return new Promise(function (accept, reject) {
126-
if (postUnpack.length === 0) {
132+
const packageJsonPath = path.join(destination, 'package.json');
133+
if (!fs.existsSync(packageJsonPath)) {
127134
return accept();
128135
}
129136

130-
exec(postUnpack, { cwd: destination }, function (err, stdout, stderr) {
131-
if (err) return reject(err);
132-
accept(stdout, stderr);
133-
});
137+
const result = spawnSync('npm', ['install'], { cwd: destination, stdio: 'ignore', shell: true });
138+
if (result.error) {
139+
return reject(result.error);
140+
}
141+
142+
if (result.status !== 0) {
143+
return reject(new Error('Failed to install box dependencies using npm install'));
144+
}
145+
146+
accept();
134147
});
135148
}
136149

137150
module.exports = {
138-
checkDestination: checkDestination,
139-
verifyURL: verifyURL,
140-
setupTempDirectory: setupTempDirectory,
141-
fetchRepository: fetchRepository,
142-
copyTempIntoDestination: copyTempIntoDestination,
143-
readBoxConfig: readBoxConfig,
144-
cleanupUnpack: cleanupUnpack,
145-
installBoxDependencies: installBoxDependencies
151+
checkDestination,
152+
verifyURL,
153+
setupTempDirectory,
154+
fetchRepository,
155+
copyTempIntoDestination,
156+
readBoxConfig,
157+
cleanupUnpack,
158+
installBoxDependencies
146159
};

0 commit comments

Comments
 (0)