From 0122188c22c5be363915fb5259f2988d02a1bf7a Mon Sep 17 00:00:00 2001 From: dapplion Date: Sat, 13 Jul 2019 23:44:33 +0200 Subject: [PATCH 1/7] Explicitly test EVMScriptRunner.protectState modifier Test setAppId also --- .../evmscript/EVMScriptExecutorMalicious.sol | 24 +++++++++++++ test/contracts/evmscript/evm_script.js | 34 +++++++++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 contracts/test/mocks/evmscript/EVMScriptExecutorMalicious.sol diff --git a/contracts/test/mocks/evmscript/EVMScriptExecutorMalicious.sol b/contracts/test/mocks/evmscript/EVMScriptExecutorMalicious.sol new file mode 100644 index 000000000..7d3646ae3 --- /dev/null +++ b/contracts/test/mocks/evmscript/EVMScriptExecutorMalicious.sol @@ -0,0 +1,24 @@ +pragma solidity ^0.4.24; + +import "../../../common/UnstructuredStorage.sol"; +import "../../../evmscript/executors/BaseEVMScriptExecutor.sol"; +import "../../../apps/AppStorage.sol"; +import "../../../kernel/IKernel.sol"; + + +contract EVMScriptExecutorMalicious is BaseEVMScriptExecutor, AppStorage { + bytes32 internal constant EXECUTOR_TYPE = keccak256("MALICIOUS_SCRIPT"); + + function execScript(bytes script, bytes, address[]) external isInitialized returns (bytes) { + // Use the script bytes variable to toggle between calling setKernel() and setAppId() + if (script[5] == 0x0) { + setKernel(IKernel(address(1))); + } else { + setAppId(bytes32(1)); + } + } + + function executorType() external pure returns (bytes32) { + return EXECUTOR_TYPE; + } +} diff --git a/test/contracts/evmscript/evm_script.js b/test/contracts/evmscript/evm_script.js index 3b36ae593..a2dfa47ee 100644 --- a/test/contracts/evmscript/evm_script.js +++ b/test/contracts/evmscript/evm_script.js @@ -19,6 +19,7 @@ const ExecutionTarget = artifacts.require('ExecutionTarget') const EVMScriptExecutorMock = artifacts.require('EVMScriptExecutorMock') const EVMScriptExecutorNoReturnMock = artifacts.require('EVMScriptExecutorNoReturnMock') const EVMScriptExecutorRevertMock = artifacts.require('EVMScriptExecutorRevertMock') +const EVMScriptExecutorMalicious = artifacts.require('EVMScriptExecutorMalicious') const EVMScriptRegistryConstantsMock = artifacts.require('EVMScriptRegistryConstantsMock') const ZERO_ADDR = '0x0000000000000000000000000000000000000000' @@ -359,6 +360,39 @@ contract('EVM Script', ([_, boss]) => { }) }) + context('> State changing script', () => { + beforeEach(async () => { + // Deploy malicious executor + const scriptExecutorMalicious = await EVMScriptExecutorMalicious.new() + + // Install mock reverting executor onto registry + await acl.createPermission(boss, evmScriptReg.address, REGISTRY_ADD_EXECUTOR_ROLE, boss, { from: boss }) + const receipt = await evmScriptReg.addScriptExecutor(scriptExecutorMalicious.address, { from: boss }) + + // Sanity check it's at spec ID 1 + const executorSpecId = getEventArgument(receipt, 'EnableExecutor', 'executorId') + const [, executorEnabled] = await evmScriptReg.executors(executorSpecId) + assert.equal(executorSpecId, 1, 'EVMScriptExecutorMalicious should be installed as spec ID 1') + assert.isTrue(executorEnabled, "malicious executor should be enabled") + }) + + it('fails if the kernel address changes', async () => { + // EVMScriptExecutorMalicious will call setKernel() + // if the address is zero + const action = { to: ZERO_ADDR, calldata: "0x0" } + const script = encodeCallScript([action]) + await assertRevert(scriptRunnerApp.runScript(script), reverts.EVMRUN_PROTECTED_STATE_MODIFIED) + }) + + it('fails if appId changes', async () => { + // EVMScriptExecutorMalicious will call setAppId() + // if the address is NOT zero + const action = { to: "0x"+"ff".repeat(20), calldata: "0x0" } + const script = encodeCallScript([action]) + await assertRevert(scriptRunnerApp.runScript(script), reverts.EVMRUN_PROTECTED_STATE_MODIFIED) + }) + }) + context('> CallsScript', () => { let callsScriptBase, executionTarget From fbf0fad555d39e1e7bc98dccd364c67e3c5c3361 Mon Sep 17 00:00:00 2001 From: Brett Sun Date: Mon, 15 Jul 2019 17:22:58 +0200 Subject: [PATCH 2/7] chore: upgrade solidity-coverage to v0.6+ (#541) --- .solcover.js | 1 - package.json | 2 +- test/contracts/apps/app_funds.js | 2 +- test/contracts/apps/recovery_to_vault.js | 30 ++++++++---------------- test/contracts/kernel/kernel_funds.js | 2 +- test/helpers/assertThrow.js | 2 +- test/helpers/coverage.js | 14 ----------- 7 files changed, 14 insertions(+), 39 deletions(-) delete mode 100644 test/helpers/coverage.js diff --git a/.solcover.js b/.solcover.js index 38a69357e..706360613 100644 --- a/.solcover.js +++ b/.solcover.js @@ -3,7 +3,6 @@ const skipFiles = [ 'test', 'acl/ACLSyntaxSugar.sol', 'common/DepositableStorage.sol', // Used in tests that send ETH - 'common/SafeERC20.sol', // solidity-coverage fails on assembly if (https://github.com/sc-forks/solidity-coverage/issues/287) 'common/UnstructuredStorage.sol' // Used in tests that send ETH ] diff --git a/package.json b/package.json index ca57aac09..5bea6fdc1 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,7 @@ "ethereumjs-abi": "^0.6.5", "ganache-cli": "^6.4.2", "mocha-lcov-reporter": "^1.3.0", - "solidity-coverage": "0.5.8", + "solidity-coverage": "^0.6.2", "solium": "^1.2.3", "truffle": "4.1.14", "truffle-bytecode-manager": "^1.1.1", diff --git a/test/contracts/apps/app_funds.js b/test/contracts/apps/app_funds.js index 623736272..f94433287 100644 --- a/test/contracts/apps/app_funds.js +++ b/test/contracts/apps/app_funds.js @@ -1,7 +1,7 @@ const { hash } = require('eth-ens-namehash') const { onlyIf } = require('../../helpers/onlyIf') -const { getBalance } = require('../../helpers/web3') const { assertRevert } = require('../../helpers/assertThrow') +const { getBalance } = require('../../helpers/web3') const ACL = artifacts.require('ACL') const Kernel = artifacts.require('Kernel') diff --git a/test/contracts/apps/recovery_to_vault.js b/test/contracts/apps/recovery_to_vault.js index 6f5e2010c..626bc67de 100644 --- a/test/contracts/apps/recovery_to_vault.js +++ b/test/contracts/apps/recovery_to_vault.js @@ -1,9 +1,8 @@ const { hash } = require('eth-ens-namehash') -const { getBalance } = require('../../helpers/web3') -const { skipCoverage } = require('../../helpers/coverage') +const { assertAmountOfEvents, assertEvent } = require('../../helpers/assertEvent')(web3) const { assertRevert } = require('../../helpers/assertThrow') const { getNewProxyAddress } = require('../../helpers/events') -const { assertAmountOfEvents, assertEvent } = require('../../helpers/assertEvent')(web3) +const { getBalance } = require('../../helpers/web3') const ACL = artifacts.require('ACL') const Kernel = artifacts.require('Kernel') @@ -160,15 +159,6 @@ contract('Recovery to vault', ([permissionsRoot]) => { // Test both the Vault itself and when it's behind a proxy to make sure their recovery behaviours are the same for (const vaultType of ['Vault', 'VaultProxy']) { - const skipCoverageIfVaultProxy = test => { - // The VaultMock isn't instrumented during coverage, but the AppProxy is, and so - // transferring to the fallback fails when we're testing with the proxy. - // Native transfers (either .send() or .transfer()) fail under coverage because they're - // limited to 2.3k gas, and the injected instrumentation from coverage makes these - // operations cost more than that limit. - return vaultType === 'VaultProxy' ? skipCoverage(test) : test - } - context(`> ${vaultType}`, () => { let target, vault @@ -218,9 +208,9 @@ contract('Recovery to vault', ([permissionsRoot]) => { await target.enableDeposits() }) - it('does not recover ETH', skipCoverageIfVaultProxy(async () => + it('does not recover ETH', async () => await recoverEth({ target, vault, shouldFail: true }) - )) + ) it('does not recover tokens', async () => await recoverTokens({ @@ -251,9 +241,9 @@ contract('Recovery to vault', ([permissionsRoot]) => { await assertRevert(target.sendTransaction({ value: 1, data: '0x01', gas: SEND_ETH_GAS })) }) - it('recovers ETH', skipCoverageIfVaultProxy(async () => + it('recovers ETH', async () => await recoverEth({ target, vault }) - )) + ) for (const { title, tokenContract } of tokenTestGroups) { it(`recovers ${title}`, async () => { @@ -289,10 +279,10 @@ contract('Recovery to vault', ([permissionsRoot]) => { target = app }) - it('does not allow recovering ETH', skipCoverageIfVaultProxy(async () => + it('does not allow recovering ETH', async () => // Conditional stub doesnt allow eth recoveries await recoverEth({ target, vault, shouldFail: true }) - )) + ) for (const { title, tokenContract } of tokenTestGroups) { it(`allows recovers ${title}`, async () => { @@ -344,8 +334,8 @@ contract('Recovery to vault', ([permissionsRoot]) => { await kernel.setRecoveryVaultAppId(vaultId) }) - it('recovers ETH from the kernel', skipCoverage(async () => { + it('recovers ETH from the kernel', async () => { await recoverEth({ target: kernel, vault }) - })) + }) }) }) diff --git a/test/contracts/kernel/kernel_funds.js b/test/contracts/kernel/kernel_funds.js index 8a6c044a1..de80d198e 100644 --- a/test/contracts/kernel/kernel_funds.js +++ b/test/contracts/kernel/kernel_funds.js @@ -1,6 +1,6 @@ +const { assertRevert } = require('../../helpers/assertThrow') const { onlyIf } = require('../../helpers/onlyIf') const { getBalance } = require('../../helpers/web3') -const { assertRevert } = require('../../helpers/assertThrow') const ACL = artifacts.require('ACL') const Kernel = artifacts.require('Kernel') diff --git a/test/helpers/assertThrow.js b/test/helpers/assertThrow.js index c15565328..e70f6c26e 100644 --- a/test/helpers/assertThrow.js +++ b/test/helpers/assertThrow.js @@ -31,7 +31,7 @@ module.exports = { error.reason = error.message.replace(errorPrefix, '').trim() } - if (process.env.SOLIDITY_COVERAGE !== 'true' && reason) { + if (reason) { assert.equal(error.reason, reason, `Expected revert reason "${reason}" but failed with "${error.reason || 'no reason'}" instead.`) } }, diff --git a/test/helpers/coverage.js b/test/helpers/coverage.js deleted file mode 100644 index f5f313242..000000000 --- a/test/helpers/coverage.js +++ /dev/null @@ -1,14 +0,0 @@ -const skipCoverage = test => { - // Required dynamic this binding to attach onto the running test - return function skipCoverage() { - if (process.env.SOLIDITY_COVERAGE === 'true') { - this.skip() - } else { - return test() - } - } -} - -module.exports = { - skipCoverage -} From 4feb97afc8f23b1bf5f89b2a3c8bb18f9c8f8923 Mon Sep 17 00:00:00 2001 From: Facu Spagnuolo Date: Mon, 15 Jul 2019 13:05:59 -0300 Subject: [PATCH 3/7] SafeERC20: Add safe total supply (#543) --- contracts/common/SafeERC20.sol | 13 +++++++++++++ contracts/test/mocks/lib/token/SafeERC20Mock.sol | 4 ++++ test/contracts/common/safe_erc20.js | 6 ++++++ 3 files changed, 23 insertions(+) diff --git a/contracts/common/SafeERC20.sol b/contracts/common/SafeERC20.sol index fa11c0921..9a6afd27b 100644 --- a/contracts/common/SafeERC20.sol +++ b/contracts/common/SafeERC20.sol @@ -153,4 +153,17 @@ library SafeERC20 { return allowance; } + + /** + * @dev Static call into ERC20.totalSupply(). + * Reverts if the call fails for some reason (should never fail). + */ + function staticTotalSupply(ERC20 _token) internal view returns (uint256) { + bytes memory totalSupplyCallData = abi.encodeWithSelector(_token.totalSupply.selector); + + (bool success, uint256 totalSupply) = staticInvoke(_token, totalSupplyCallData); + require(success, ERROR_TOKEN_ALLOWANCE_REVERTED); + + return totalSupply; + } } diff --git a/contracts/test/mocks/lib/token/SafeERC20Mock.sol b/contracts/test/mocks/lib/token/SafeERC20Mock.sol index 9f13848f6..d1f83369d 100644 --- a/contracts/test/mocks/lib/token/SafeERC20Mock.sol +++ b/contracts/test/mocks/lib/token/SafeERC20Mock.sol @@ -33,4 +33,8 @@ contract SafeERC20Mock { function balanceOf(ERC20 token, address owner) external view returns (uint256) { return token.staticBalanceOf(owner); } + + function totalSupply(ERC20 token) external view returns (uint256) { + return token.staticTotalSupply(); + } } diff --git a/test/contracts/common/safe_erc20.js b/test/contracts/common/safe_erc20.js index 00c08a311..2b8d58505 100644 --- a/test/contracts/common/safe_erc20.js +++ b/test/contracts/common/safe_erc20.js @@ -120,6 +120,12 @@ contract('SafeERC20', ([owner, receiver]) => { assert.equal(balance, initialBalance, 'Mock should return correct balance') assert.equal((await tokenMock.balanceOf(owner)).valueOf(), balance, "Mock should match token contract's balance") }) + + it('gives correct value with static totalSupply', async () => { + const totalSupply = (await safeERC20Mock.totalSupply(tokenMock.address)).valueOf() + assert.equal(totalSupply, initialBalance, 'Mock should return correct total supply') + assert.equal((await tokenMock.totalSupply()).valueOf(), totalSupply, "Mock should match token contract's total supply") + }) }) } }) From c3508233f0a885579d17724b5d2ff47c3cacb897 Mon Sep 17 00:00:00 2001 From: cgewecke Date: Thu, 1 Aug 2019 07:28:31 -0700 Subject: [PATCH 4/7] CI: Add gas check report (#547) --- .travis.yml | 5 +++++ codechecks.yml | 2 ++ package.json | 4 +++- 3 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 codechecks.yml diff --git a/.travis.yml b/.travis.yml index d0fb40bfc..c09fb0d8f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,6 +10,11 @@ env: - TASK=lint - TASK=test - TASK=coverage + - TASK=test:gas:ci +matrix: + fast_finish: true + allow_failures: + - env: TASK=test:gas:ci before_script: - npm prune script: "npm run $TASK" diff --git a/codechecks.yml b/codechecks.yml new file mode 100644 index 000000000..8a630425b --- /dev/null +++ b/codechecks.yml @@ -0,0 +1,2 @@ +checks: + - name: eth-gas-reporter/codechecks diff --git a/package.json b/package.json index 5bea6fdc1..36cceadc2 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,7 @@ "compile": "truffle compile", "test": "TRUFFLE_TEST=true npm run ganache-cli:test", "test:gas": "GAS_REPORTER=true npm test", + "test:gas:ci": "npm run test:gas && npx codechecks", "lint": "solium --dir ./contracts", "coverage": "SOLIDITY_COVERAGE=true npm run ganache-cli:test", "console": "truffle dev", @@ -33,9 +34,10 @@ "repository": "https://github.com/aragon/aragonOS", "license": "(GPL-3.0-or-later OR MIT)", "devDependencies": { + "@codechecks/client": "^0.1.5", "coveralls": "^2.13.3", "eth-ens-namehash": "^2.0.8", - "eth-gas-reporter": "^0.1.1", + "eth-gas-reporter": "^0.2.9", "ethereumjs-abi": "^0.6.5", "ganache-cli": "^6.4.2", "mocha-lcov-reporter": "^1.3.0", From d520e204cd8d84d231170bdd34140c84b18b1769 Mon Sep 17 00:00:00 2001 From: dapplion Date: Mon, 19 Aug 2019 22:08:56 +0200 Subject: [PATCH 5/7] Test AppProxyFactory methods without initialization payload --- test/contracts/factory/app_proxy_factory.js | 80 +++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 test/contracts/factory/app_proxy_factory.js diff --git a/test/contracts/factory/app_proxy_factory.js b/test/contracts/factory/app_proxy_factory.js new file mode 100644 index 000000000..a700ae7e9 --- /dev/null +++ b/test/contracts/factory/app_proxy_factory.js @@ -0,0 +1,80 @@ +const { hash } = require('eth-ens-namehash') +const { assertEvent } = require('../../helpers/assertEvent')(web3) +const { getEventArgument } = require('../../helpers/events') +const web3EthAbi = require('web3-eth-abi'); + +const ACL = artifacts.require('ACL') +const Kernel = artifacts.require('Kernel') +const KernelProxy = artifacts.require('KernelProxy') +const AppStorage = artifacts.require('AppStorage') +const AppProxyFactory = artifacts.require('AppProxyFactory') +const AppStub = artifacts.require('AppStub') + +// Mocks +const APP_ID = hash('stub.aragonpm.test') + +contract('App Proxy Factory', accounts => { + let aclBase, kernel, kernelBase, appBase, appProxyFactory + let APP_BASES_NAMESPACE + + const permissionsRoot = accounts[0] + + before(async () => { + aclBase = await ACL.new() + appBase = await AppStub.new() + + // Setup constants + kernelBase = await Kernel.new(true) + APP_BASES_NAMESPACE = await kernelBase.APP_BASES_NAMESPACE() + kernel = Kernel.at((await KernelProxy.new(kernelBase.address)).address) + await kernel.initialize(aclBase.address, permissionsRoot) + acl = ACL.at(await kernel.acl()) + + // Set up app management permissions + const APP_MANAGER_ROLE = await kernelBase.APP_MANAGER_ROLE() + await acl.createPermission(permissionsRoot, kernel.address, APP_MANAGER_ROLE, permissionsRoot) + + // Set app + await kernel.setApp(APP_BASES_NAMESPACE, APP_ID, appBase.address) + + // Deploy test instance + appProxyFactory = await AppProxyFactory.new() + }) + + it('deploys a new App Proxy without initialization payload', async () => { + const receipt = await appProxyFactory.newAppProxy(kernel.address, APP_ID) + + assertEvent(receipt, 'NewAppProxy', { isUpgradeable: true, appId: APP_ID }) + + const appProxy = AppStorage.at(getEventArgument(receipt, 'NewAppProxy', 'proxy')) + assert.equal(await appProxy.kernel(), kernel.address, 'should have set the correct kernel') + assert.equal(await appProxy.appId(), APP_ID, 'should have set the correct appId') + }) + + it('deploys a new App Proxy Pinned without initialization payload', async () => { + // Manually sending the transaction to overcome truffle@4.x limitations with overloaded functions + const receipt = await appProxyFactory.sendTransaction({ + from: permissionsRoot, + data: web3EthAbi.encodeFunctionCall({ + "constant": false, + "inputs": [ + { "name": "_kernel", "type": "address" }, + { "name": "_appId", "type": "bytes32" } + ], + "name": "newAppProxyPinned", + "outputs": [ + { "name": "", "type": "address" } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, [kernel.address, APP_ID]) + }) + + assertEvent(receipt, 'NewAppProxy', { isUpgradeable: false, appId: APP_ID }) + + const appProxy = AppStorage.at(getEventArgument(receipt, 'NewAppProxy', 'proxy')) + assert.equal(await appProxy.kernel(), kernel.address, 'should have set the correct kernel') + assert.equal(await appProxy.appId(), APP_ID, 'should have set the correct appId') + }) +}) From 85fc5b5a13a885748fb6aa3d0cf3e89b602f7820 Mon Sep 17 00:00:00 2001 From: dapplion Date: Sat, 31 Aug 2019 13:59:11 +0200 Subject: [PATCH 6/7] Test reverting static methods of SafeERC20.sol Format context string --- .../lib/token/TokenRevertViewMethods.sol | 47 +++++++++++++++++++ test/contracts/common/safe_erc20.js | 32 +++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 contracts/test/mocks/lib/token/TokenRevertViewMethods.sol diff --git a/contracts/test/mocks/lib/token/TokenRevertViewMethods.sol b/contracts/test/mocks/lib/token/TokenRevertViewMethods.sol new file mode 100644 index 000000000..8919486b5 --- /dev/null +++ b/contracts/test/mocks/lib/token/TokenRevertViewMethods.sol @@ -0,0 +1,47 @@ +// Modified from https://github.com/OpenZeppelin/openzeppelin-solidity/blob/a9f910d34f0ab33a1ae5e714f69f9596a02b4d91/contracts/token/ERC20/StandardToken.sol + +pragma solidity 0.4.24; + +import "../../../../lib/math/SafeMath.sol"; + + +contract TokenRevertViewMethods { + using SafeMath for uint256; + mapping (address => uint256) private balances; + mapping (address => mapping (address => uint256)) private allowed; + uint256 private totalSupply_; + bool private allowTransfer_; + + // Allow us to set the inital balance for an account on construction + constructor(address initialAccount, uint256 initialBalance) public { + balances[initialAccount] = initialBalance; + totalSupply_ = initialBalance; + allowTransfer_ = true; + } + + function totalSupply() public view returns (uint256) { + require(false, "MOCK_ERROR"); + return totalSupply_; + } + + /** + * @dev Gets the balance of the specified address. + * @param _owner The address to query the the balance of. + * @return An uint256 representing the amount owned by the passed address. + */ + function balanceOf(address _owner) public view returns (uint256) { + require(false, "MOCK_ERROR"); + return balances[_owner]; + } + + /** + * @dev Function to check the amount of tokens that an owner allowed to a spender. + * @param _owner address The address which owns the funds. + * @param _spender address The address which will spend the funds. + * @return A uint256 specifying the amount of tokens still available for the spender. + */ + function allowance(address _owner, address _spender) public view returns (uint256) { + require(false, "MOCK_ERROR"); + return allowed[_owner][_spender]; + } +} diff --git a/test/contracts/common/safe_erc20.js b/test/contracts/common/safe_erc20.js index 2b8d58505..f3940aec2 100644 --- a/test/contracts/common/safe_erc20.js +++ b/test/contracts/common/safe_erc20.js @@ -1,10 +1,13 @@ const { getEventArgument } = require('../../helpers/events') +const { assertRevert } = require('../../helpers/assertThrow') +const reverts = require('../../helpers/revertStrings') // Mocks const SafeERC20Mock = artifacts.require('SafeERC20Mock') const TokenMock = artifacts.require('TokenMock') const TokenReturnFalseMock = artifacts.require('TokenReturnFalseMock') const TokenReturnMissingMock = artifacts.require('TokenReturnMissingMock') +const TokenRevertViewMethods = artifacts.require('TokenRevertViewMethods') const assertMockResult = (receipt, result) => assert.equal(getEventArgument(receipt, 'Result', 'result'), result, `result does not match`) @@ -128,4 +131,33 @@ contract('SafeERC20', ([owner, receiver]) => { }) }) } + + context('> Reverting view methods', () => { + let tokenMock + + beforeEach(async () => { + tokenMock = await TokenRevertViewMethods.new(owner, initialBalance) + }) + + it('allowance', async () => { + await assertRevert( + safeERC20Mock.allowance(tokenMock.address, owner, owner), + reverts.SAFE_ERC_20_ALLOWANCE_REVERTED + ) + }) + + it('balanceOf', async () => { + await assertRevert( + safeERC20Mock.balanceOf(tokenMock.address, owner), + reverts.SAFE_ERC_20_BALANCE_REVERTED + ) + }) + + it('totalSupply', async () => { + await assertRevert( + safeERC20Mock.totalSupply(tokenMock.address), + reverts.SAFE_ERC_20_ALLOWANCE_REVERTED + ) + }) + }) }) From 9013714de3512ffcb5dbd515a65ed5bda7e10ca0 Mon Sep 17 00:00:00 2001 From: dapplion Date: Tue, 17 Sep 2019 16:49:23 +0200 Subject: [PATCH 7/7] Bump solidity-coverage to fix bug from solidity-parser-antlr --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 36cceadc2..31f20a3bb 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,7 @@ "ethereumjs-abi": "^0.6.5", "ganache-cli": "^6.4.2", "mocha-lcov-reporter": "^1.3.0", - "solidity-coverage": "^0.6.2", + "solidity-coverage": "^0.6.7", "solium": "^1.2.3", "truffle": "4.1.14", "truffle-bytecode-manager": "^1.1.1",