diff options
Diffstat (limited to 'packages/contracts')
9 files changed, 105 insertions, 30 deletions
diff --git a/packages/contracts/package.json b/packages/contracts/package.json index d6ca3727b..2495795dc 100644 --- a/packages/contracts/package.json +++ b/packages/contracts/package.json @@ -19,6 +19,7 @@ "rebuild_and_test": "run-s build test", "test:coverage": "SOLIDITY_COVERAGE=true run-s build run_mocha coverage:report:text coverage:report:lcov", "test:profiler": "SOLIDITY_PROFILER=true run-s build run_mocha profiler:report:html", + "test:trace": "SOLIDITY_REVERT_TRACE=true run-s build run_mocha", "run_mocha": "mocha --require source-map-support/register 'lib/test/**/*.js' --timeout 100000 --bail --exit", "compile": "sol-compiler", "clean": "shx rm -rf lib src/generated_contract_wrappers", diff --git a/packages/contracts/src/contracts/current/protocol/AssetProxy/ERC20Proxy.sol b/packages/contracts/src/contracts/current/protocol/AssetProxy/ERC20Proxy.sol index ddcd78e93..eeddb9707 100644 --- a/packages/contracts/src/contracts/current/protocol/AssetProxy/ERC20Proxy.sol +++ b/packages/contracts/src/contracts/current/protocol/AssetProxy/ERC20Proxy.sol @@ -50,7 +50,35 @@ contract ERC20Proxy is address token = readAddress(assetData, 0); // Transfer tokens. - bool success = IERC20Token(token).transferFrom(from, to, amount); + // We do a raw call so we can check the success separate + // from the return data. + bool success = token.call(abi.encodeWithSelector( + IERC20Token(token).transferFrom.selector, + from, + to, + amount + )); + require( + success, + TRANSFER_FAILED + ); + + // Check return data. + // If there is no return data, we assume the token incorrectly + // does not return a bool. In this case we expect it to revert + // on failure, which was handled above. + // If the token does return data, we require that it is a single + // value that evaluates to true. + assembly { + if returndatasize { + success := 0 + if eq(returndatasize, 32) { + // First 64 bytes of memory are reserved scratch space + returndatacopy(0, 0, 32) + success := mload(0) + } + } + } require( success, TRANSFER_FAILED diff --git a/packages/contracts/src/contracts/current/protocol/Exchange/MixinSignatureValidator.sol b/packages/contracts/src/contracts/current/protocol/Exchange/MixinSignatureValidator.sol index 1a556dfe2..8ad15aaff 100644 --- a/packages/contracts/src/contracts/current/protocol/Exchange/MixinSignatureValidator.sol +++ b/packages/contracts/src/contracts/current/protocol/Exchange/MixinSignatureValidator.sol @@ -82,7 +82,7 @@ contract MixinSignatureValidator is address signer, bytes memory signature ) - internal + public view returns (bool isValid) { diff --git a/packages/contracts/src/contracts/current/protocol/Exchange/MixinWrapperFunctions.sol b/packages/contracts/src/contracts/current/protocol/Exchange/MixinWrapperFunctions.sol index a7849f4cb..724f95518 100644 --- a/packages/contracts/src/contracts/current/protocol/Exchange/MixinWrapperFunctions.sol +++ b/packages/contracts/src/contracts/current/protocol/Exchange/MixinWrapperFunctions.sol @@ -263,40 +263,50 @@ contract MixinWrapperFunctions is /// @param orders Array of order specifications. /// @param takerAssetFillAmounts Array of desired amounts of takerAsset to sell in orders. /// @param signatures Proofs that orders have been created by makers. + /// @return Amounts filled and fees paid by makers and taker. + /// NOTE: makerAssetFilledAmount and takerAssetFilledAmount may include amounts filled of different assets. function batchFillOrders( LibOrder.Order[] memory orders, uint256[] memory takerAssetFillAmounts, bytes[] memory signatures ) public + returns (FillResults memory totalFillResults) { for (uint256 i = 0; i < orders.length; i++) { - fillOrder( + FillResults memory singleFillResults = fillOrder( orders[i], takerAssetFillAmounts[i], signatures[i] ); + addFillResults(totalFillResults, singleFillResults); } + return totalFillResults; } /// @dev Synchronously executes multiple calls of fillOrKill. /// @param orders Array of order specifications. /// @param takerAssetFillAmounts Array of desired amounts of takerAsset to sell in orders. /// @param signatures Proofs that orders have been created by makers. + /// @return Amounts filled and fees paid by makers and taker. + /// NOTE: makerAssetFilledAmount and takerAssetFilledAmount may include amounts filled of different assets. function batchFillOrKillOrders( LibOrder.Order[] memory orders, uint256[] memory takerAssetFillAmounts, bytes[] memory signatures ) public + returns (FillResults memory totalFillResults) { for (uint256 i = 0; i < orders.length; i++) { - fillOrKillOrder( + FillResults memory singleFillResults = fillOrKillOrder( orders[i], takerAssetFillAmounts[i], signatures[i] ); + addFillResults(totalFillResults, singleFillResults); } + return totalFillResults; } /// @dev Fills an order with specified parameters and ECDSA signature. @@ -304,20 +314,25 @@ contract MixinWrapperFunctions is /// @param orders Array of order specifications. /// @param takerAssetFillAmounts Array of desired amounts of takerAsset to sell in orders. /// @param signatures Proofs that orders have been created by makers. + /// @return Amounts filled and fees paid by makers and taker. + /// NOTE: makerAssetFilledAmount and takerAssetFilledAmount may include amounts filled of different assets. function batchFillOrdersNoThrow( LibOrder.Order[] memory orders, uint256[] memory takerAssetFillAmounts, bytes[] memory signatures ) public + returns (FillResults memory totalFillResults) { for (uint256 i = 0; i < orders.length; i++) { - fillOrderNoThrow( + FillResults memory singleFillResults = fillOrderNoThrow( orders[i], takerAssetFillAmounts[i], signatures[i] ); + addFillResults(totalFillResults, singleFillResults); } + return totalFillResults; } /// @dev Synchronously executes multiple calls of fillOrder until total amount of takerAsset is sold by taker. diff --git a/packages/contracts/src/contracts/current/protocol/Exchange/interfaces/ISignatureValidator.sol b/packages/contracts/src/contracts/current/protocol/Exchange/interfaces/ISignatureValidator.sol index 26e360c91..02aa9776e 100644 --- a/packages/contracts/src/contracts/current/protocol/Exchange/interfaces/ISignatureValidator.sol +++ b/packages/contracts/src/contracts/current/protocol/Exchange/interfaces/ISignatureValidator.sol @@ -39,4 +39,18 @@ contract ISignatureValidator { bool approval ) external; + + /// @dev Verifies that a signature is valid. + /// @param hash Message hash that is signed. + /// @param signer Address of signer. + /// @param signature Proof of signing. + /// @return Validity of order signature. + function isValidSignature( + bytes32 hash, + address signer, + bytes memory signature + ) + public + view + returns (bool isValid); } diff --git a/packages/contracts/src/contracts/current/protocol/Exchange/interfaces/IWrapperFunctions.sol b/packages/contracts/src/contracts/current/protocol/Exchange/interfaces/IWrapperFunctions.sol index acd4f359c..84bb683bc 100644 --- a/packages/contracts/src/contracts/current/protocol/Exchange/interfaces/IWrapperFunctions.sol +++ b/packages/contracts/src/contracts/current/protocol/Exchange/interfaces/IWrapperFunctions.sol @@ -22,10 +22,7 @@ pragma experimental ABIEncoderV2; import "../libs/LibOrder.sol"; import "../libs/LibFillResults.sol"; -contract IWrapperFunctions is - LibOrder, - LibFillResults -{ +contract IWrapperFunctions { /// @dev Fills the input order. Reverts if exact takerAssetFillAmount not filled. /// @param order LibOrder.Order struct containing order specifications. /// @param takerAssetFillAmount Desired amount of takerAsset to sell. @@ -56,35 +53,41 @@ contract IWrapperFunctions is /// @param orders Array of order specifications. /// @param takerAssetFillAmounts Array of desired amounts of takerAsset to sell in orders. /// @param signatures Proofs that orders have been created by makers. + /// @return Amounts filled and fees paid by makers and taker. function batchFillOrders( LibOrder.Order[] memory orders, uint256[] memory takerAssetFillAmounts, bytes[] memory signatures ) - public; + public + returns (LibFillResults.FillResults memory totalFillResults); /// @dev Synchronously executes multiple calls of fillOrKill. /// @param orders Array of order specifications. /// @param takerAssetFillAmounts Array of desired amounts of takerAsset to sell in orders. /// @param signatures Proofs that orders have been created by makers. + /// @return Amounts filled and fees paid by makers and taker. function batchFillOrKillOrders( LibOrder.Order[] memory orders, uint256[] memory takerAssetFillAmounts, bytes[] memory signatures ) - public; + public + returns (LibFillResults.FillResults memory totalFillResults); /// @dev Fills an order with specified parameters and ECDSA signature. /// Returns false if the transaction would otherwise revert. /// @param orders Array of order specifications. /// @param takerAssetFillAmounts Array of desired amounts of takerAsset to sell in orders. /// @param signatures Proofs that orders have been created by makers. + /// @return Amounts filled and fees paid by makers and taker. function batchFillOrdersNoThrow( LibOrder.Order[] memory orders, uint256[] memory takerAssetFillAmounts, bytes[] memory signatures ) - public; + public + returns (LibFillResults.FillResults memory totalFillResults); /// @dev Synchronously executes multiple calls of fillOrder until total amount of takerAsset is sold by taker. /// @param orders Array of order specifications. diff --git a/packages/contracts/src/contracts/current/protocol/Exchange/mixins/MSignatureValidator.sol b/packages/contracts/src/contracts/current/protocol/Exchange/mixins/MSignatureValidator.sol index 7eed453ff..5e286e43a 100644 --- a/packages/contracts/src/contracts/current/protocol/Exchange/mixins/MSignatureValidator.sol +++ b/packages/contracts/src/contracts/current/protocol/Exchange/mixins/MSignatureValidator.sol @@ -35,18 +35,4 @@ contract MSignatureValidator is PreSigned, // 0x07 Trezor // 0x08 } - - /// @dev Verifies that a signature is valid. - /// @param hash Message hash that is signed. - /// @param signer Address of signer. - /// @param signature Proof of signing. - /// @return Validity of order signature. - function isValidSignature( - bytes32 hash, - address signer, - bytes memory signature - ) - internal - view - returns (bool isValid); } diff --git a/packages/contracts/src/utils/revert_trace.ts b/packages/contracts/src/utils/revert_trace.ts new file mode 100644 index 000000000..0bf8384bc --- /dev/null +++ b/packages/contracts/src/utils/revert_trace.ts @@ -0,0 +1,21 @@ +import { devConstants } from '@0xproject/dev-utils'; +import { RevertTraceSubprovider, SolCompilerArtifactAdapter } from '@0xproject/sol-cov'; +import * as _ from 'lodash'; + +let revertTraceSubprovider: RevertTraceSubprovider; + +export const revertTrace = { + getRevertTraceSubproviderSingleton(): RevertTraceSubprovider { + if (_.isUndefined(revertTraceSubprovider)) { + revertTraceSubprovider = revertTrace._getRevertTraceSubprovider(); + } + return revertTraceSubprovider; + }, + _getRevertTraceSubprovider(): RevertTraceSubprovider { + const defaultFromAddress = devConstants.TESTRPC_FIRST_ADDRESS; + const solCompilerArtifactAdapter = new SolCompilerArtifactAdapter(); + const isVerbose = true; + const subprovider = new RevertTraceSubprovider(solCompilerArtifactAdapter, defaultFromAddress, isVerbose); + return subprovider; + }, +}; diff --git a/packages/contracts/src/utils/web3_wrapper.ts b/packages/contracts/src/utils/web3_wrapper.ts index c475d96a9..c9d83a02d 100644 --- a/packages/contracts/src/utils/web3_wrapper.ts +++ b/packages/contracts/src/utils/web3_wrapper.ts @@ -2,9 +2,11 @@ import { devConstants, env, EnvVars, web3Factory } from '@0xproject/dev-utils'; import { prependSubprovider } from '@0xproject/subproviders'; import { logUtils } from '@0xproject/utils'; import { Web3Wrapper } from '@0xproject/web3-wrapper'; +import * as _ from 'lodash'; import { coverage } from './coverage'; import { profiler } from './profiler'; +import { revertTrace } from './revert_trace'; enum ProviderType { Ganache = 'ganache', @@ -48,10 +50,11 @@ const providerConfigs = testProvider === ProviderType.Ganache ? ganacheConfigs : export const provider = web3Factory.getRpcProvider(providerConfigs); const isCoverageEnabled = env.parseBoolean(EnvVars.SolidityCoverage); const isProfilerEnabled = env.parseBoolean(EnvVars.SolidityProfiler); -if (isCoverageEnabled && isProfilerEnabled) { - throw new Error( - `Unfortunately for now you can't enable both coverage and profiler at the same time. They both use coverage.json file and there is no way to configure that.`, - ); +const isRevertTraceEnabled = env.parseBoolean(EnvVars.SolidityRevertTrace); +const enabledSubproviderCount = _.filter([isCoverageEnabled, isProfilerEnabled, isRevertTraceEnabled], _.identity) + .length; +if (enabledSubproviderCount > 1) { + throw new Error(`Only one of coverage, profiler, or revert trace subproviders can be enabled at a time`); } if (isCoverageEnabled) { const coverageSubprovider = coverage.getCoverageSubproviderSingleton(); @@ -71,5 +74,9 @@ if (isProfilerEnabled) { profilerSubprovider.stop(); prependSubprovider(provider, profilerSubprovider); } +if (isRevertTraceEnabled) { + const revertTraceSubprovider = revertTrace.getRevertTraceSubproviderSingleton(); + prependSubprovider(provider, revertTraceSubprovider); +} export const web3Wrapper = new Web3Wrapper(provider); |