aboutsummaryrefslogtreecommitdiffstats
path: root/contracts
diff options
context:
space:
mode:
Diffstat (limited to 'contracts')
-rw-r--r--contracts/.solhint.json1
-rw-r--r--contracts/examples/package.json3
-rw-r--r--contracts/extensions/CHANGELOG.json17
-rw-r--r--contracts/extensions/compiler.json2
-rw-r--r--contracts/extensions/contracts/BalanceThresholdFilter/MixinBalanceThresholdFilterCore.sol2
-rw-r--r--contracts/extensions/contracts/BalanceThresholdFilter/MixinExchangeCalldata.sol2
-rw-r--r--contracts/extensions/contracts/BalanceThresholdFilter/interfaces/IBalanceThresholdFilterCore.sol2
-rw-r--r--contracts/extensions/contracts/BalanceThresholdFilter/interfaces/IThresholdAsset.sol2
-rw-r--r--contracts/extensions/contracts/BalanceThresholdFilter/mixins/MBalanceThresholdFilterCore.sol2
-rw-r--r--contracts/extensions/contracts/BalanceThresholdFilter/mixins/MExchangeCalldata.sol2
-rw-r--r--contracts/extensions/contracts/Forwarder/MixinAssets.sol2
-rw-r--r--contracts/extensions/contracts/Forwarder/MixinExchangeWrapper.sol2
-rw-r--r--contracts/extensions/contracts/Forwarder/MixinForwarderCore.sol2
-rw-r--r--contracts/extensions/contracts/Forwarder/MixinWeth.sol2
-rw-r--r--contracts/extensions/contracts/Forwarder/interfaces/IAssets.sol2
-rw-r--r--contracts/extensions/contracts/Forwarder/interfaces/IForwarder.sol2
-rw-r--r--contracts/extensions/contracts/Forwarder/interfaces/IForwarderCore.sol2
-rw-r--r--contracts/extensions/contracts/Forwarder/libs/LibConstants.sol2
-rw-r--r--contracts/extensions/contracts/Forwarder/libs/LibForwarderErrors.sol2
-rw-r--r--contracts/extensions/contracts/Forwarder/mixins/MAssets.sol2
-rw-r--r--contracts/extensions/contracts/Forwarder/mixins/MExchangeWrapper.sol2
-rw-r--r--contracts/extensions/contracts/Forwarder/mixins/MWeth.sol2
-rw-r--r--contracts/extensions/contracts/OrderMatcher/MixinAssets.sol195
-rw-r--r--contracts/extensions/contracts/OrderMatcher/MixinMatchOrders.sol86
-rw-r--r--contracts/extensions/contracts/OrderMatcher/OrderMatcher.sol38
-rw-r--r--contracts/extensions/contracts/OrderMatcher/interfaces/IAssets.sol43
-rw-r--r--contracts/extensions/contracts/OrderMatcher/interfaces/IMatchOrders.sol43
-rw-r--r--contracts/extensions/contracts/OrderMatcher/interfaces/IOrderMatcher.sol31
-rw-r--r--contracts/extensions/contracts/OrderMatcher/libs/LibConstants.sol56
-rw-r--r--contracts/extensions/contracts/OrderMatcher/mixins/MAssets.sol71
-rw-r--r--contracts/extensions/contracts/OrderValidator/OrderValidator.sol (renamed from contracts/protocol/contracts/protocol/OrderValidator/OrderValidator.sol)0
-rw-r--r--contracts/extensions/package.json6
-rw-r--r--contracts/extensions/src/artifacts/index.ts4
-rw-r--r--contracts/extensions/src/wrappers/index.ts2
-rw-r--r--contracts/extensions/test/extensions/dutch_auction.ts194
-rw-r--r--contracts/extensions/test/extensions/forwarder.ts3
-rw-r--r--contracts/extensions/test/extensions/order_matcher.ts818
-rw-r--r--contracts/extensions/test/extensions/order_validator.ts (renamed from contracts/protocol/test/exchange/order_validator.ts)23
-rw-r--r--contracts/extensions/test/utils/dutch_auction_test_wrapper.ts62
-rw-r--r--contracts/extensions/tsconfig.json4
-rw-r--r--contracts/interfaces/contracts/protocol/AssetProxy/IAssetData.sol2
-rw-r--r--contracts/interfaces/contracts/protocol/AssetProxy/IAssetProxy.sol2
-rw-r--r--contracts/interfaces/contracts/protocol/AssetProxy/IAuthorizable.sol2
-rw-r--r--contracts/interfaces/contracts/protocol/Exchange/IAssetProxyDispatcher.sol2
-rw-r--r--contracts/interfaces/contracts/protocol/Exchange/IExchange.sol2
-rw-r--r--contracts/interfaces/contracts/protocol/Exchange/IExchangeCore.sol2
-rw-r--r--contracts/interfaces/contracts/protocol/Exchange/IMatchOrders.sol2
-rw-r--r--contracts/interfaces/contracts/protocol/Exchange/ISignatureValidator.sol2
-rw-r--r--contracts/interfaces/contracts/protocol/Exchange/ITransactions.sol2
-rw-r--r--contracts/interfaces/contracts/protocol/Exchange/IValidator.sol2
-rw-r--r--contracts/interfaces/contracts/protocol/Exchange/IWallet.sol2
-rw-r--r--contracts/interfaces/contracts/protocol/Exchange/IWrapperFunctions.sol2
-rw-r--r--contracts/interfaces/package.json3
-rw-r--r--contracts/libs/compiler.json11
-rw-r--r--contracts/libs/contracts/libs/LibAbiEncoder.sol2
-rw-r--r--contracts/libs/contracts/libs/LibAddressArray.sol2
-rw-r--r--contracts/libs/contracts/libs/LibAssetProxyErrors.sol2
-rw-r--r--contracts/libs/contracts/libs/LibConstants.sol2
-rw-r--r--contracts/libs/contracts/libs/LibEIP712.sol2
-rw-r--r--contracts/libs/contracts/libs/LibExchangeErrors.sol2
-rw-r--r--contracts/libs/contracts/libs/LibExchangeSelectors.sol2
-rw-r--r--contracts/libs/contracts/libs/LibFillResults.sol2
-rw-r--r--contracts/libs/contracts/libs/LibMath.sol2
-rw-r--r--contracts/libs/contracts/libs/LibOrder.sol2
-rw-r--r--contracts/libs/package.json3
-rw-r--r--contracts/multisig/package.json3
-rw-r--r--contracts/protocol/CHANGELOG.json8
-rw-r--r--contracts/protocol/compiler.json1
-rw-r--r--contracts/protocol/contracts/protocol/AssetProxy/MixinAuthorizable.sol2
-rw-r--r--contracts/protocol/contracts/protocol/AssetProxy/MultiAssetProxy.sol14
-rw-r--r--contracts/protocol/contracts/protocol/AssetProxy/mixins/MAuthorizable.sol2
-rw-r--r--contracts/protocol/contracts/protocol/Exchange/MixinAssetProxyDispatcher.sol2
-rw-r--r--contracts/protocol/contracts/protocol/Exchange/MixinExchangeCore.sol2
-rw-r--r--contracts/protocol/contracts/protocol/Exchange/MixinMatchOrders.sol2
-rw-r--r--contracts/protocol/contracts/protocol/Exchange/MixinSignatureValidator.sol2
-rw-r--r--contracts/protocol/contracts/protocol/Exchange/MixinTransactions.sol2
-rw-r--r--contracts/protocol/contracts/protocol/Exchange/MixinWrapperFunctions.sol2
-rw-r--r--contracts/protocol/contracts/protocol/Exchange/mixins/MAssetProxyDispatcher.sol2
-rw-r--r--contracts/protocol/contracts/protocol/Exchange/mixins/MExchangeCore.sol2
-rw-r--r--contracts/protocol/contracts/protocol/Exchange/mixins/MMatchOrders.sol2
-rw-r--r--contracts/protocol/contracts/protocol/Exchange/mixins/MSignatureValidator.sol2
-rw-r--r--contracts/protocol/contracts/protocol/Exchange/mixins/MTransactions.sol2
-rw-r--r--contracts/protocol/contracts/protocol/Exchange/mixins/MWrapperFunctions.sol2
-rw-r--r--contracts/protocol/package.json5
-rw-r--r--contracts/protocol/src/artifacts/index.ts2
-rw-r--r--contracts/protocol/src/wrappers/index.ts1
-rw-r--r--contracts/protocol/test/asset_proxy/proxies.ts64
-rw-r--r--contracts/protocol/test/exchange/core.ts31
-rw-r--r--contracts/protocol/tsconfig.json1
-rw-r--r--contracts/test-utils/src/constants.ts1
-rw-r--r--contracts/tokens/contracts/tokens/ERC20Token/ERC20Token.sol2
-rw-r--r--contracts/tokens/contracts/tokens/ERC20Token/IERC20Token.sol2
-rw-r--r--contracts/tokens/contracts/tokens/ERC20Token/MintableERC20Token.sol2
-rw-r--r--contracts/tokens/contracts/tokens/ERC20Token/UnlimitedAllowanceERC20Token.sol2
-rw-r--r--contracts/tokens/contracts/tokens/ERC721Token/ERC721Token.sol2
-rw-r--r--contracts/tokens/contracts/tokens/ERC721Token/IERC721Receiver.sol2
-rw-r--r--contracts/tokens/contracts/tokens/ERC721Token/IERC721Token.sol2
-rw-r--r--contracts/tokens/contracts/tokens/ERC721Token/MintableERC721Token.sol2
-rw-r--r--contracts/tokens/contracts/tokens/EtherToken/IEtherToken.sol2
-rw-r--r--contracts/tokens/package.json3
-rw-r--r--contracts/tokens/src/artifacts/index.ts1
-rw-r--r--contracts/utils/contracts/utils/LibBytes/LibBytes.sol2
-rw-r--r--contracts/utils/contracts/utils/Ownable/IOwnable.sol2
-rw-r--r--contracts/utils/contracts/utils/Ownable/Ownable.sol2
-rw-r--r--contracts/utils/contracts/utils/ReentrancyGuard/ReentrancyGuard.sol2
-rw-r--r--contracts/utils/contracts/utils/SafeMath/SafeMath.sol2
-rw-r--r--contracts/utils/package.json3
107 files changed, 1711 insertions, 282 deletions
diff --git a/contracts/.solhint.json b/contracts/.solhint.json
index 076afe9f3..3090d981a 100644
--- a/contracts/.solhint.json
+++ b/contracts/.solhint.json
@@ -5,6 +5,7 @@
"avoid-tx-origin": "warn",
"bracket-align": false,
"code-complexity": false,
+ "compiler-fixed": false,
"const-name-snakecase": "error",
"expression-indent": "error",
"function-max-lines": false,
diff --git a/contracts/examples/package.json b/contracts/examples/package.json
index 77846241e..37b73f98c 100644
--- a/contracts/examples/package.json
+++ b/contracts/examples/package.json
@@ -13,7 +13,8 @@
"build": "yarn pre_build && tsc -b",
"build:ci": "yarn build",
"pre_build": "run-s compile generate_contract_wrappers",
- "compile": "sol-compiler --contracts-dir contracts",
+ "compile": "sol-compiler",
+ "watch": "sol-compiler -w",
"clean": "shx rm -rf lib generated-artifacts generated-wrappers",
"generate_contract_wrappers": "abi-gen --abis ${npm_package_config_abis} --template ../../node_modules/@0x/abi-gen-templates/contract.handlebars --partials '../../node_modules/@0x/abi-gen-templates/partials/**/*.handlebars' --output generated-wrappers --backend ethers",
"lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
diff --git a/contracts/extensions/CHANGELOG.json b/contracts/extensions/CHANGELOG.json
index da4d9c2ba..40e25565e 100644
--- a/contracts/extensions/CHANGELOG.json
+++ b/contracts/extensions/CHANGELOG.json
@@ -1,10 +1,27 @@
[
{
+ "version": "1.2.0",
+ "changes": [
+ {
+ "note": "Added Dutch Auction Wrapper",
+ "pr": 1465
+ }
+ ]
+ },
+ {
"version": "1.1.0",
"changes": [
{
"note": "Added Balance Threshold Filter",
"pr": 1383
+ },
+ {
+ "note": "Add OrderMatcher",
+ "pr": 1117
+ },
+ {
+ "note": "Add OrderValidator",
+ "pr": 1464
}
]
},
diff --git a/contracts/extensions/compiler.json b/contracts/extensions/compiler.json
index e6ed0c215..2bb468724 100644
--- a/contracts/extensions/compiler.json
+++ b/contracts/extensions/compiler.json
@@ -18,5 +18,5 @@
}
}
},
- "contracts": ["BalanceThresholdFilter", "DutchAuction", "Forwarder"]
+ "contracts": ["BalanceThresholdFilter", "DutchAuction", "Forwarder", "OrderMatcher", "OrderValidator"]
}
diff --git a/contracts/extensions/contracts/BalanceThresholdFilter/MixinBalanceThresholdFilterCore.sol b/contracts/extensions/contracts/BalanceThresholdFilter/MixinBalanceThresholdFilterCore.sol
index df830f36e..da050bf72 100644
--- a/contracts/extensions/contracts/BalanceThresholdFilter/MixinBalanceThresholdFilterCore.sol
+++ b/contracts/extensions/contracts/BalanceThresholdFilter/MixinBalanceThresholdFilterCore.sol
@@ -16,7 +16,7 @@
*/
-pragma solidity 0.4.24;
+pragma solidity ^0.4.24;
import "@0x/contracts-libs/contracts/libs/LibExchangeSelectors.sol";
import "@0x/contracts-libs/contracts/libs/LibOrder.sol";
diff --git a/contracts/extensions/contracts/BalanceThresholdFilter/MixinExchangeCalldata.sol b/contracts/extensions/contracts/BalanceThresholdFilter/MixinExchangeCalldata.sol
index bd26a468f..a15e95a9d 100644
--- a/contracts/extensions/contracts/BalanceThresholdFilter/MixinExchangeCalldata.sol
+++ b/contracts/extensions/contracts/BalanceThresholdFilter/MixinExchangeCalldata.sol
@@ -17,7 +17,7 @@
*/
-pragma solidity 0.4.24;
+pragma solidity ^0.4.24;
import "./mixins/MExchangeCalldata.sol";
import "@0x/contracts-libs/contracts/libs/LibAddressArray.sol";
diff --git a/contracts/extensions/contracts/BalanceThresholdFilter/interfaces/IBalanceThresholdFilterCore.sol b/contracts/extensions/contracts/BalanceThresholdFilter/interfaces/IBalanceThresholdFilterCore.sol
index 3d8e2bbd1..4a1bf1fb2 100644
--- a/contracts/extensions/contracts/BalanceThresholdFilter/interfaces/IBalanceThresholdFilterCore.sol
+++ b/contracts/extensions/contracts/BalanceThresholdFilter/interfaces/IBalanceThresholdFilterCore.sol
@@ -17,7 +17,7 @@
*/
-pragma solidity 0.4.24;
+pragma solidity ^0.4.24;
contract IBalanceThresholdFilterCore {
diff --git a/contracts/extensions/contracts/BalanceThresholdFilter/interfaces/IThresholdAsset.sol b/contracts/extensions/contracts/BalanceThresholdFilter/interfaces/IThresholdAsset.sol
index 3e424b9f4..f78f9c2de 100644
--- a/contracts/extensions/contracts/BalanceThresholdFilter/interfaces/IThresholdAsset.sol
+++ b/contracts/extensions/contracts/BalanceThresholdFilter/interfaces/IThresholdAsset.sol
@@ -16,7 +16,7 @@
*/
-pragma solidity 0.4.24;
+pragma solidity ^0.4.24;
contract IThresholdAsset {
diff --git a/contracts/extensions/contracts/BalanceThresholdFilter/mixins/MBalanceThresholdFilterCore.sol b/contracts/extensions/contracts/BalanceThresholdFilter/mixins/MBalanceThresholdFilterCore.sol
index b8b67e6ee..074686e8d 100644
--- a/contracts/extensions/contracts/BalanceThresholdFilter/mixins/MBalanceThresholdFilterCore.sol
+++ b/contracts/extensions/contracts/BalanceThresholdFilter/mixins/MBalanceThresholdFilterCore.sol
@@ -16,7 +16,7 @@
*/
-pragma solidity 0.4.24;
+pragma solidity ^0.4.24;
import "@0x/contracts-interfaces/contracts/protocol/Exchange/IExchange.sol";
import "../interfaces/IThresholdAsset.sol";
diff --git a/contracts/extensions/contracts/BalanceThresholdFilter/mixins/MExchangeCalldata.sol b/contracts/extensions/contracts/BalanceThresholdFilter/mixins/MExchangeCalldata.sol
index bf2940fe1..40536d820 100644
--- a/contracts/extensions/contracts/BalanceThresholdFilter/mixins/MExchangeCalldata.sol
+++ b/contracts/extensions/contracts/BalanceThresholdFilter/mixins/MExchangeCalldata.sol
@@ -17,7 +17,7 @@
*/
-pragma solidity 0.4.24;
+pragma solidity ^0.4.24;
contract MExchangeCalldata {
diff --git a/contracts/extensions/contracts/Forwarder/MixinAssets.sol b/contracts/extensions/contracts/Forwarder/MixinAssets.sol
index 3ebf75161..116cdf267 100644
--- a/contracts/extensions/contracts/Forwarder/MixinAssets.sol
+++ b/contracts/extensions/contracts/Forwarder/MixinAssets.sol
@@ -16,7 +16,7 @@
*/
-pragma solidity 0.4.24;
+pragma solidity ^0.4.24;
import "@0x/contracts-utils/contracts/utils/LibBytes/LibBytes.sol";
import "@0x/contracts-utils/contracts/utils/Ownable/Ownable.sol";
diff --git a/contracts/extensions/contracts/Forwarder/MixinExchangeWrapper.sol b/contracts/extensions/contracts/Forwarder/MixinExchangeWrapper.sol
index 210eb14c2..cab26741d 100644
--- a/contracts/extensions/contracts/Forwarder/MixinExchangeWrapper.sol
+++ b/contracts/extensions/contracts/Forwarder/MixinExchangeWrapper.sol
@@ -16,7 +16,7 @@
*/
-pragma solidity 0.4.24;
+pragma solidity ^0.4.24;
pragma experimental ABIEncoderV2;
import "./libs/LibConstants.sol";
diff --git a/contracts/extensions/contracts/Forwarder/MixinForwarderCore.sol b/contracts/extensions/contracts/Forwarder/MixinForwarderCore.sol
index bab78d79b..11c0147a5 100644
--- a/contracts/extensions/contracts/Forwarder/MixinForwarderCore.sol
+++ b/contracts/extensions/contracts/Forwarder/MixinForwarderCore.sol
@@ -16,7 +16,7 @@
*/
-pragma solidity 0.4.24;
+pragma solidity ^0.4.24;
pragma experimental ABIEncoderV2;
import "./libs/LibConstants.sol";
diff --git a/contracts/extensions/contracts/Forwarder/MixinWeth.sol b/contracts/extensions/contracts/Forwarder/MixinWeth.sol
index 2a281f3ae..25a35f47b 100644
--- a/contracts/extensions/contracts/Forwarder/MixinWeth.sol
+++ b/contracts/extensions/contracts/Forwarder/MixinWeth.sol
@@ -16,7 +16,7 @@
*/
-pragma solidity 0.4.24;
+pragma solidity ^0.4.24;
import "@0x/contracts-libs/contracts/libs/LibMath.sol";
import "./libs/LibConstants.sol";
diff --git a/contracts/extensions/contracts/Forwarder/interfaces/IAssets.sol b/contracts/extensions/contracts/Forwarder/interfaces/IAssets.sol
index 1e034c003..cebfd3706 100644
--- a/contracts/extensions/contracts/Forwarder/interfaces/IAssets.sol
+++ b/contracts/extensions/contracts/Forwarder/interfaces/IAssets.sol
@@ -16,7 +16,7 @@
*/
-pragma solidity 0.4.24;
+pragma solidity ^0.4.24;
contract IAssets {
diff --git a/contracts/extensions/contracts/Forwarder/interfaces/IForwarder.sol b/contracts/extensions/contracts/Forwarder/interfaces/IForwarder.sol
index f5a26e2ba..6ce8a1d31 100644
--- a/contracts/extensions/contracts/Forwarder/interfaces/IForwarder.sol
+++ b/contracts/extensions/contracts/Forwarder/interfaces/IForwarder.sol
@@ -16,7 +16,7 @@
*/
-pragma solidity 0.4.24;
+pragma solidity ^0.4.24;
pragma experimental ABIEncoderV2;
import "./IForwarderCore.sol";
diff --git a/contracts/extensions/contracts/Forwarder/interfaces/IForwarderCore.sol b/contracts/extensions/contracts/Forwarder/interfaces/IForwarderCore.sol
index eede20bb8..7f62722e7 100644
--- a/contracts/extensions/contracts/Forwarder/interfaces/IForwarderCore.sol
+++ b/contracts/extensions/contracts/Forwarder/interfaces/IForwarderCore.sol
@@ -16,7 +16,7 @@
*/
-pragma solidity 0.4.24;
+pragma solidity ^0.4.24;
pragma experimental ABIEncoderV2;
import "@0x/contracts-libs/contracts/libs/LibOrder.sol";
diff --git a/contracts/extensions/contracts/Forwarder/libs/LibConstants.sol b/contracts/extensions/contracts/Forwarder/libs/LibConstants.sol
index 4a81abf76..0d2f6e36d 100644
--- a/contracts/extensions/contracts/Forwarder/libs/LibConstants.sol
+++ b/contracts/extensions/contracts/Forwarder/libs/LibConstants.sol
@@ -16,7 +16,7 @@
*/
-pragma solidity 0.4.24;
+pragma solidity ^0.4.24;
import "@0x/contracts-utils/contracts/utils/LibBytes/LibBytes.sol";
import "@0x/contracts-interfaces/contracts/protocol/Exchange/IExchange.sol";
diff --git a/contracts/extensions/contracts/Forwarder/libs/LibForwarderErrors.sol b/contracts/extensions/contracts/Forwarder/libs/LibForwarderErrors.sol
index fb3ade1db..7a95b78a0 100644
--- a/contracts/extensions/contracts/Forwarder/libs/LibForwarderErrors.sol
+++ b/contracts/extensions/contracts/Forwarder/libs/LibForwarderErrors.sol
@@ -17,7 +17,7 @@
*/
// solhint-disable
-pragma solidity 0.4.24;
+pragma solidity ^0.4.24;
/// This contract is intended to serve as a reference, but is not actually used for efficiency reasons.
diff --git a/contracts/extensions/contracts/Forwarder/mixins/MAssets.sol b/contracts/extensions/contracts/Forwarder/mixins/MAssets.sol
index 9e7f80d97..1757b37fb 100644
--- a/contracts/extensions/contracts/Forwarder/mixins/MAssets.sol
+++ b/contracts/extensions/contracts/Forwarder/mixins/MAssets.sol
@@ -16,7 +16,7 @@
*/
-pragma solidity 0.4.24;
+pragma solidity ^0.4.24;
import "../interfaces/IAssets.sol";
diff --git a/contracts/extensions/contracts/Forwarder/mixins/MExchangeWrapper.sol b/contracts/extensions/contracts/Forwarder/mixins/MExchangeWrapper.sol
index d9e71786a..143f888b1 100644
--- a/contracts/extensions/contracts/Forwarder/mixins/MExchangeWrapper.sol
+++ b/contracts/extensions/contracts/Forwarder/mixins/MExchangeWrapper.sol
@@ -16,7 +16,7 @@
*/
-pragma solidity 0.4.24;
+pragma solidity ^0.4.24;
pragma experimental ABIEncoderV2;
import "@0x/contracts-libs/contracts/libs/LibOrder.sol";
diff --git a/contracts/extensions/contracts/Forwarder/mixins/MWeth.sol b/contracts/extensions/contracts/Forwarder/mixins/MWeth.sol
index 88e77be4e..15d66942f 100644
--- a/contracts/extensions/contracts/Forwarder/mixins/MWeth.sol
+++ b/contracts/extensions/contracts/Forwarder/mixins/MWeth.sol
@@ -16,7 +16,7 @@
*/
-pragma solidity 0.4.24;
+pragma solidity ^0.4.24;
contract MWeth {
diff --git a/contracts/extensions/contracts/OrderMatcher/MixinAssets.sol b/contracts/extensions/contracts/OrderMatcher/MixinAssets.sol
new file mode 100644
index 000000000..f0f91cfc0
--- /dev/null
+++ b/contracts/extensions/contracts/OrderMatcher/MixinAssets.sol
@@ -0,0 +1,195 @@
+/*
+
+ Copyright 2018 ZeroEx Intl.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+*/
+
+pragma solidity ^0.4.24;
+
+import "@0x/contracts-utils/contracts/utils/LibBytes/LibBytes.sol";
+import "@0x/contracts-utils/contracts/utils/Ownable/Ownable.sol";
+import "@0x/contracts-tokens/contracts/tokens/ERC20Token/IERC20Token.sol";
+import "@0x/contracts-tokens/contracts/tokens/ERC721Token/IERC721Token.sol";
+import "./mixins/MAssets.sol";
+import "./libs/LibConstants.sol";
+
+
+contract MixinAssets is
+ MAssets,
+ Ownable,
+ LibConstants
+{
+ using LibBytes for bytes;
+
+ /// @dev Withdraws assets from this contract. The contract requires a ZRX balance in order to
+ /// function optimally, and this function allows the ZRX to be withdrawn by owner. It may also be
+ /// used to withdraw assets that were accidentally sent to this contract.
+ /// @param assetData Byte array encoded for the respective asset proxy.
+ /// @param amount Amount of asset to withdraw.
+ function withdrawAsset(
+ bytes assetData,
+ uint256 amount
+ )
+ external
+ onlyOwner
+ {
+ transferAssetToSender(assetData, amount);
+ }
+
+ /// @dev Approves or disapproves an AssetProxy to spend asset.
+ /// @param assetData Byte array encoded for the respective asset proxy.
+ /// @param amount Amount of asset to approve for respective proxy.
+ function approveAssetProxy(
+ bytes assetData,
+ uint256 amount
+ )
+ external
+ onlyOwner
+ {
+ bytes4 proxyId = assetData.readBytes4(0);
+
+ if (proxyId == ERC20_DATA_ID) {
+ approveERC20Token(assetData, amount);
+ } else if (proxyId == ERC721_DATA_ID) {
+ approveERC721Token(assetData, amount);
+ } else {
+ revert("UNSUPPORTED_ASSET_PROXY");
+ }
+ }
+
+ /// @dev Transfers given amount of asset to sender.
+ /// @param assetData Byte array encoded for the respective asset proxy.
+ /// @param amount Amount of asset to transfer to sender.
+ function transferAssetToSender(
+ bytes memory assetData,
+ uint256 amount
+ )
+ internal
+ {
+ bytes4 proxyId = assetData.readBytes4(0);
+
+ if (proxyId == ERC20_DATA_ID) {
+ transferERC20Token(assetData, amount);
+ } else if (proxyId == ERC721_DATA_ID) {
+ transferERC721Token(assetData, amount);
+ } else {
+ revert("UNSUPPORTED_ASSET_PROXY");
+ }
+ }
+
+ /// @dev Decodes ERC20 assetData and transfers given amount to sender.
+ /// @param assetData Byte array encoded for the respective asset proxy.
+ /// @param amount Amount of asset to transfer to sender.
+ function transferERC20Token(
+ bytes memory assetData,
+ uint256 amount
+ )
+ internal
+ {
+ // 4 byte id + 12 0 bytes before ABI encoded token address.
+ address token = assetData.readAddress(16);
+
+ // Transfer tokens.
+ // We do a raw call so we can check the success separate
+ // from the return data.
+ bool success = token.call(abi.encodeWithSelector(
+ ERC20_TRANSFER_SELECTOR,
+ msg.sender,
+ 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"
+ );
+ }
+
+ /// @dev Decodes ERC721 assetData and transfers given amount to sender.
+ /// @param assetData Byte array encoded for the respective asset proxy.
+ /// @param amount Amount of asset to transfer to sender.
+ function transferERC721Token(
+ bytes memory assetData,
+ uint256 amount
+ )
+ internal
+ {
+ require(
+ amount == 1,
+ "INVALID_AMOUNT"
+ );
+ // Decode asset data.
+ // 4 byte id + 12 0 bytes before ABI encoded token address.
+ address token = assetData.readAddress(16);
+ // 4 byte id + 32 byte ABI encoded token address before token id.
+ uint256 tokenId = assetData.readUint256(36);
+
+ // Perform transfer.
+ IERC721Token(token).transferFrom(
+ address(this),
+ msg.sender,
+ tokenId
+ );
+ }
+
+ /// @dev Sets approval for ERC20 AssetProxy.
+ /// @param assetData Byte array encoded for the respective asset proxy.
+ /// @param amount Amount of asset to approve for respective proxy.
+ function approveERC20Token(
+ bytes memory assetData,
+ uint256 amount
+ )
+ internal
+ {
+ address token = assetData.readAddress(16);
+ require(
+ IERC20Token(token).approve(ERC20_PROXY_ADDRESS, amount),
+ "APPROVAL_FAILED"
+ );
+ }
+
+ /// @dev Sets approval for ERC721 AssetProxy.
+ /// @param assetData Byte array encoded for the respective asset proxy.
+ /// @param amount Amount of asset to approve for respective proxy.
+ function approveERC721Token(
+ bytes memory assetData,
+ uint256 amount
+ )
+ internal
+ {
+ address token = assetData.readAddress(16);
+ bool approval = amount >= 1;
+ IERC721Token(token).setApprovalForAll(ERC721_PROXY_ADDRESS, approval);
+ }
+}
diff --git a/contracts/extensions/contracts/OrderMatcher/MixinMatchOrders.sol b/contracts/extensions/contracts/OrderMatcher/MixinMatchOrders.sol
new file mode 100644
index 000000000..1787deb59
--- /dev/null
+++ b/contracts/extensions/contracts/OrderMatcher/MixinMatchOrders.sol
@@ -0,0 +1,86 @@
+/*
+
+ Copyright 2018 ZeroEx Intl.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+*/
+
+pragma solidity ^0.4.24;
+pragma experimental ABIEncoderV2;
+
+import "./libs/LibConstants.sol";
+import "@0x/contracts-libs/contracts/libs/LibOrder.sol";
+import "@0x/contracts-libs/contracts/libs/LibFillResults.sol";
+import "@0x/contracts-utils/contracts/utils/Ownable/Ownable.sol";
+
+
+contract MixinMatchOrders is
+ Ownable,
+ LibConstants
+{
+ /// @dev Match two complementary orders that have a profitable spread.
+ /// Each order is filled at their respective price point. However, the calculations are
+ /// carried out as though the orders are both being filled at the right order's price point.
+ /// The profit made by the left order is then used to fill the right order as much as possible.
+ /// This results in a spread being taken in terms of both assets. The spread is held within this contract.
+ /// @param leftOrder First order to match.
+ /// @param rightOrder Second order to match.
+ /// @param leftSignature Proof that order was created by the left maker.
+ /// @param rightSignature Proof that order was created by the right maker.
+ function matchOrders(
+ LibOrder.Order memory leftOrder,
+ LibOrder.Order memory rightOrder,
+ bytes memory leftSignature,
+ bytes memory rightSignature
+ )
+ public
+ onlyOwner
+ {
+ // Match orders, maximally filling `leftOrder`
+ LibFillResults.MatchedFillResults memory matchedFillResults = EXCHANGE.matchOrders(
+ leftOrder,
+ rightOrder,
+ leftSignature,
+ rightSignature
+ );
+
+ uint256 leftMakerAssetSpreadAmount = matchedFillResults.leftMakerAssetSpreadAmount;
+ uint256 rightOrderTakerAssetAmount = rightOrder.takerAssetAmount;
+
+ // Do not attempt to call `fillOrder` if no spread was taken or `rightOrder` has been completely filled
+ if (leftMakerAssetSpreadAmount == 0 || matchedFillResults.right.takerAssetFilledAmount == rightOrderTakerAssetAmount) {
+ return;
+ }
+
+ // The `assetData` fields of the `rightOrder` could have been null for the `matchOrders` call. We reassign them before calling `fillOrder`.
+ rightOrder.makerAssetData = leftOrder.takerAssetData;
+ rightOrder.takerAssetData = leftOrder.makerAssetData;
+
+ // Query `rightOrder` info to check if it has been completely filled
+ // We need to make this check in case the `rightOrder` was partially filled before the `matchOrders` call
+ LibOrder.OrderInfo memory orderInfo = EXCHANGE.getOrderInfo(rightOrder);
+
+ // Do not attempt to call `fillOrder` if order has been completely filled
+ if (orderInfo.orderTakerAssetFilledAmount == rightOrderTakerAssetAmount) {
+ return;
+ }
+
+ // We do not need to pass in a signature since it was already validated in the `matchOrders` call
+ EXCHANGE.fillOrder(
+ rightOrder,
+ leftMakerAssetSpreadAmount,
+ ""
+ );
+ }
+}
diff --git a/contracts/extensions/contracts/OrderMatcher/OrderMatcher.sol b/contracts/extensions/contracts/OrderMatcher/OrderMatcher.sol
new file mode 100644
index 000000000..4879b7bca
--- /dev/null
+++ b/contracts/extensions/contracts/OrderMatcher/OrderMatcher.sol
@@ -0,0 +1,38 @@
+/*
+
+ Copyright 2018 ZeroEx Intl.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+*/
+
+pragma solidity 0.4.24;
+pragma experimental ABIEncoderV2;
+
+import "@0x/contracts-utils/contracts/utils/Ownable/Ownable.sol";
+import "./libs/LibConstants.sol";
+import "./MixinMatchOrders.sol";
+import "./MixinAssets.sol";
+
+
+// solhint-disable no-empty-blocks
+contract OrderMatcher is
+ MixinMatchOrders,
+ MixinAssets
+{
+ constructor (address _exchange)
+ public
+ LibConstants(_exchange)
+ Ownable()
+ {}
+}
diff --git a/contracts/extensions/contracts/OrderMatcher/interfaces/IAssets.sol b/contracts/extensions/contracts/OrderMatcher/interfaces/IAssets.sol
new file mode 100644
index 000000000..9fcc0023a
--- /dev/null
+++ b/contracts/extensions/contracts/OrderMatcher/interfaces/IAssets.sol
@@ -0,0 +1,43 @@
+/*
+
+ Copyright 2018 ZeroEx Intl.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+*/
+
+pragma solidity ^0.4.24;
+
+
+contract IAssets {
+
+ /// @dev Withdraws assets from this contract. The contract requires a ZRX balance in order to
+ /// function optimally, and this function allows the ZRX to be withdrawn by owner. It may also be
+ /// used to withdraw assets that were accidentally sent to this contract.
+ /// @param assetData Byte array encoded for the respective asset proxy.
+ /// @param amount Amount of asset to withdraw.
+ function withdrawAsset(
+ bytes assetData,
+ uint256 amount
+ )
+ external;
+
+ /// @dev Approves or disapproves an AssetProxy to spend asset.
+ /// @param assetData Byte array encoded for the respective asset proxy.
+ /// @param amount Amount of asset to approve for respective proxy.
+ function approveAssetProxy(
+ bytes assetData,
+ uint256 amount
+ )
+ external;
+}
diff --git a/contracts/extensions/contracts/OrderMatcher/interfaces/IMatchOrders.sol b/contracts/extensions/contracts/OrderMatcher/interfaces/IMatchOrders.sol
new file mode 100644
index 000000000..1443c73b9
--- /dev/null
+++ b/contracts/extensions/contracts/OrderMatcher/interfaces/IMatchOrders.sol
@@ -0,0 +1,43 @@
+/*
+
+ Copyright 2018 ZeroEx Intl.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+*/
+
+pragma solidity ^0.4.24;
+pragma experimental ABIEncoderV2;
+
+import "@0x/contracts-libs/contracts/libs/LibOrder.sol";
+
+
+contract IMatchOrders {
+
+ /// @dev Match two complementary orders that have a profitable spread.
+ /// Each order is filled at their respective price point. However, the calculations are
+ /// carried out as though the orders are both being filled at the right order's price point.
+ /// The profit made by the left order is then used to fill the right order as much as possible.
+ /// This results in a spread being taken in terms of both assets. The spread is held within this contract.
+ /// @param leftOrder First order to match.
+ /// @param rightOrder Second order to match.
+ /// @param leftSignature Proof that order was created by the left maker.
+ /// @param rightSignature Proof that order was created by the right maker.
+ function matchOrders(
+ LibOrder.Order memory leftOrder,
+ LibOrder.Order memory rightOrder,
+ bytes memory leftSignature,
+ bytes memory rightSignature
+ )
+ public;
+}
diff --git a/contracts/extensions/contracts/OrderMatcher/interfaces/IOrderMatcher.sol b/contracts/extensions/contracts/OrderMatcher/interfaces/IOrderMatcher.sol
new file mode 100644
index 000000000..75f26dca6
--- /dev/null
+++ b/contracts/extensions/contracts/OrderMatcher/interfaces/IOrderMatcher.sol
@@ -0,0 +1,31 @@
+/*
+
+ Copyright 2018 ZeroEx Intl.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+*/
+
+pragma solidity ^0.4.24;
+
+import "@0x/contract-utils/contracts/utils/Ownable/IOwnable.sol";
+import "./IMatchOrders.sol";
+import "./IAssets.sol";
+
+
+// solhint-disable no-empty-blocks
+contract IOrderMatcher is
+ IOwnable,
+ IMatchOrders,
+ IAssets
+{}
diff --git a/contracts/extensions/contracts/OrderMatcher/libs/LibConstants.sol b/contracts/extensions/contracts/OrderMatcher/libs/LibConstants.sol
new file mode 100644
index 000000000..c1a86a9c7
--- /dev/null
+++ b/contracts/extensions/contracts/OrderMatcher/libs/LibConstants.sol
@@ -0,0 +1,56 @@
+/*
+
+ Copyright 2018 ZeroEx Intl.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+*/
+
+pragma solidity ^0.4.24;
+
+import "@0x/contracts-interfaces/contracts/protocol/Exchange/IExchange.sol";
+
+
+contract LibConstants {
+
+ // bytes4(keccak256("transfer(address,uint256)"))
+ bytes4 constant internal ERC20_TRANSFER_SELECTOR = 0xa9059cbb;
+ // bytes4(keccak256("ERC20Token(address)"))
+ bytes4 constant internal ERC20_DATA_ID = 0xf47261b0;
+ // bytes4(keccak256("ERC721Token(address,uint256)"))
+ bytes4 constant internal ERC721_DATA_ID = 0x02571792;
+
+ // solhint-disable var-name-mixedcase
+ IExchange internal EXCHANGE;
+ address internal ERC20_PROXY_ADDRESS;
+ address internal ERC721_PROXY_ADDRESS;
+ // solhint-enable var-name-mixedcase
+
+ constructor (address _exchange)
+ public
+ {
+ EXCHANGE = IExchange(_exchange);
+
+ ERC20_PROXY_ADDRESS = EXCHANGE.getAssetProxy(ERC20_DATA_ID);
+ require(
+ ERC20_PROXY_ADDRESS != address(0),
+ "UNREGISTERED_ASSET_PROXY"
+ );
+
+ ERC721_PROXY_ADDRESS = EXCHANGE.getAssetProxy(ERC721_DATA_ID);
+ require(
+ ERC721_PROXY_ADDRESS != address(0),
+ "UNREGISTERED_ASSET_PROXY"
+ );
+ }
+}
diff --git a/contracts/extensions/contracts/OrderMatcher/mixins/MAssets.sol b/contracts/extensions/contracts/OrderMatcher/mixins/MAssets.sol
new file mode 100644
index 000000000..6ea7a3290
--- /dev/null
+++ b/contracts/extensions/contracts/OrderMatcher/mixins/MAssets.sol
@@ -0,0 +1,71 @@
+/*
+
+ Copyright 2018 ZeroEx Intl.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+*/
+
+pragma solidity ^0.4.24;
+
+import "../interfaces/IAssets.sol";
+
+
+contract MAssets is
+ IAssets
+{
+ /// @dev Transfers given amount of asset to sender.
+ /// @param assetData Byte array encoded for the respective asset proxy.
+ /// @param amount Amount of asset to transfer to sender.
+ function transferAssetToSender(
+ bytes memory assetData,
+ uint256 amount
+ )
+ internal;
+
+ /// @dev Decodes ERC20 assetData and transfers given amount to sender.
+ /// @param assetData Byte array encoded for the respective asset proxy.
+ /// @param amount Amount of asset to transfer to sender.
+ function transferERC20Token(
+ bytes memory assetData,
+ uint256 amount
+ )
+ internal;
+
+ /// @dev Decodes ERC721 assetData and transfers given amount to sender.
+ /// @param assetData Byte array encoded for the respective asset proxy.
+ /// @param amount Amount of asset to transfer to sender.
+ function transferERC721Token(
+ bytes memory assetData,
+ uint256 amount
+ )
+ internal;
+
+ /// @dev Sets approval for ERC20 AssetProxy.
+ /// @param assetData Byte array encoded for the respective asset proxy.
+ /// @param amount Amount of asset to approve for respective proxy.
+ function approveERC20Token(
+ bytes memory assetData,
+ uint256 amount
+ )
+ internal;
+
+ /// @dev Sets approval for ERC721 AssetProxy.
+ /// @param assetData Byte array encoded for the respective asset proxy.
+ /// @param amount Amount of asset to approve for respective proxy.
+ function approveERC721Token(
+ bytes memory assetData,
+ uint256 amount
+ )
+ internal;
+}
diff --git a/contracts/protocol/contracts/protocol/OrderValidator/OrderValidator.sol b/contracts/extensions/contracts/OrderValidator/OrderValidator.sol
index 33dd1326c..33dd1326c 100644
--- a/contracts/protocol/contracts/protocol/OrderValidator/OrderValidator.sol
+++ b/contracts/extensions/contracts/OrderValidator/OrderValidator.sol
diff --git a/contracts/extensions/package.json b/contracts/extensions/package.json
index 2d9ed4dcd..aee995645 100644
--- a/contracts/extensions/package.json
+++ b/contracts/extensions/package.json
@@ -19,7 +19,8 @@
"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 --require make-promises-safe 'lib/test/**/*.js' --timeout 100000 --bail --exit",
- "compile": "sol-compiler --contracts-dir contracts",
+ "compile": "sol-compiler",
+ "watch": "sol-compiler -w",
"clean": "shx rm -rf lib generated-artifacts generated-wrappers",
"generate_contract_wrappers": "abi-gen --abis ${npm_package_config_abis} --template ../../node_modules/@0x/abi-gen-templates/contract.handlebars --partials '../../node_modules/@0x/abi-gen-templates/partials/**/*.handlebars' --output generated-wrappers --backend ethers",
"lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
@@ -31,7 +32,7 @@
"lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol"
},
"config": {
- "abis": "generated-artifacts/@(BalanceThresholdFilter|DutchAuction|Forwarder).json"
+ "abis": "generated-artifacts/@(BalanceThresholdFilter|DutchAuction|Forwarder|OrderMatcher|OrderValidator).json"
},
"repository": {
"type": "git",
@@ -44,6 +45,7 @@
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/extensions/README.md",
"devDependencies": {
"@0x/abi-gen": "^1.0.19",
+ "@0x/contract-wrappers": "^4.1.3",
"@0x/contracts-test-utils": "^1.0.2",
"@0x/dev-utils": "^1.0.21",
"@0x/sol-compiler": "^1.1.16",
diff --git a/contracts/extensions/src/artifacts/index.ts b/contracts/extensions/src/artifacts/index.ts
index ebf0b8050..329d0f3f3 100644
--- a/contracts/extensions/src/artifacts/index.ts
+++ b/contracts/extensions/src/artifacts/index.ts
@@ -3,9 +3,13 @@ import { ContractArtifact } from 'ethereum-types';
import * as BalanceThresholdFilter from '../../generated-artifacts/BalanceThresholdFilter.json';
import * as DutchAuction from '../../generated-artifacts/DutchAuction.json';
import * as Forwarder from '../../generated-artifacts/Forwarder.json';
+import * as OrderMatcher from '../../generated-artifacts/OrderMatcher.json';
+import * as OrderValidator from '../../generated-artifacts/OrderValidator.json';
export const artifacts = {
BalanceThresholdFilter: BalanceThresholdFilter as ContractArtifact,
DutchAuction: DutchAuction as ContractArtifact,
Forwarder: Forwarder as ContractArtifact,
+ OrderMatcher: OrderMatcher as ContractArtifact,
+ OrderValidator: OrderValidator as ContractArtifact,
};
diff --git a/contracts/extensions/src/wrappers/index.ts b/contracts/extensions/src/wrappers/index.ts
index 8a8122caa..65aec3ccd 100644
--- a/contracts/extensions/src/wrappers/index.ts
+++ b/contracts/extensions/src/wrappers/index.ts
@@ -1,3 +1,5 @@
export * from '../../generated-wrappers/balance_threshold_filter';
export * from '../../generated-wrappers/dutch_auction';
export * from '../../generated-wrappers/forwarder';
+export * from '../../generated-wrappers/order_matcher';
+export * from '../../generated-wrappers/order_validator';
diff --git a/contracts/extensions/test/extensions/dutch_auction.ts b/contracts/extensions/test/extensions/dutch_auction.ts
index 6c3b2f0f3..22b3caa16 100644
--- a/contracts/extensions/test/extensions/dutch_auction.ts
+++ b/contracts/extensions/test/extensions/dutch_auction.ts
@@ -1,3 +1,4 @@
+import { DutchAuctionWrapper } from '@0x/contract-wrappers';
import {
artifacts as protocolArtifacts,
ERC20Wrapper,
@@ -29,12 +30,11 @@ import { RevertReason, SignedOrder } from '@0x/types';
import { BigNumber } from '@0x/utils';
import { Web3Wrapper } from '@0x/web3-wrapper';
import * as chai from 'chai';
-import ethAbi = require('ethereumjs-abi');
-import * as ethUtil from 'ethereumjs-util';
import * as _ from 'lodash';
import { DutchAuctionContract } from '../../generated-wrappers/dutch_auction';
import { artifacts } from '../../src/artifacts';
+import { DutchAuctionTestWrapper } from '../utils/dutch_auction_test_wrapper';
chaiSetup.configure();
const expect = chai.expect;
@@ -68,19 +68,8 @@ describe(ContractName.DutchAuction, () => {
let erc721MakerAssetIds: BigNumber[];
const tenMinutesInSeconds = 10 * 60;
- function extendMakerAssetData(makerAssetData: string, beginTimeSeconds: BigNumber, beginAmount: BigNumber): string {
- return ethUtil.bufferToHex(
- Buffer.concat([
- ethUtil.toBuffer(makerAssetData),
- ethUtil.toBuffer(
- (ethAbi as any).rawEncode(
- ['uint256', 'uint256'],
- [beginTimeSeconds.toString(), beginAmount.toString()],
- ),
- ),
- ]),
- );
- }
+ let dutchAuctionTestWrapper: DutchAuctionTestWrapper;
+ let defaultERC20MakerAssetData: string;
before(async () => {
await blockchainLifecycle.startAsync();
@@ -136,6 +125,7 @@ describe(ContractName.DutchAuction, () => {
dutchAuctionInstance.address,
provider,
);
+ dutchAuctionTestWrapper = new DutchAuctionTestWrapper(dutchAuctionInstance, provider);
defaultMakerAssetAddress = erc20TokenA.address;
const defaultTakerAssetAddress = wethContract.address;
@@ -174,7 +164,7 @@ describe(ContractName.DutchAuction, () => {
feeRecipientAddress,
// taker address or sender address should be set to the ducth auction contract
takerAddress: dutchAuctionContract.address,
- makerAssetData: extendMakerAssetData(
+ makerAssetData: DutchAuctionWrapper.encodeDutchAuctionAssetData(
assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress),
auctionBeginTimeSeconds,
auctionBeginAmount,
@@ -199,6 +189,7 @@ describe(ContractName.DutchAuction, () => {
const takerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(takerAddress)];
sellerOrderFactory = new OrderFactory(makerPrivateKey, sellerDefaultOrderParams);
buyerOrderFactory = new OrderFactory(takerPrivateKey, buyerDefaultOrderParams);
+ defaultERC20MakerAssetData = assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress);
});
after(async () => {
await blockchainLifecycle.revertAsync();
@@ -215,49 +206,41 @@ describe(ContractName.DutchAuction, () => {
describe('matchOrders', () => {
it('should be worth the begin price at the begining of the auction', async () => {
auctionBeginTimeSeconds = new BigNumber(currentBlockTimestamp + 2);
- sellOrder = await sellerOrderFactory.newSignedOrderAsync({
- makerAssetData: extendMakerAssetData(
- assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress),
- auctionBeginTimeSeconds,
- auctionBeginAmount,
- ),
- });
- const auctionDetails = await dutchAuctionContract.getAuctionDetails.callAsync(sellOrder);
+ const makerAssetData = DutchAuctionWrapper.encodeDutchAuctionAssetData(
+ defaultERC20MakerAssetData,
+ auctionBeginTimeSeconds,
+ auctionBeginAmount,
+ );
+ sellOrder = await sellerOrderFactory.newSignedOrderAsync({ makerAssetData });
+ const auctionDetails = await dutchAuctionTestWrapper.getAuctionDetailsAsync(sellOrder);
+ expect(auctionDetails.currentTimeSeconds).to.be.bignumber.lte(auctionBeginTimeSeconds);
expect(auctionDetails.currentAmount).to.be.bignumber.equal(auctionBeginAmount);
expect(auctionDetails.beginAmount).to.be.bignumber.equal(auctionBeginAmount);
});
it('should be be worth the end price at the end of the auction', async () => {
auctionBeginTimeSeconds = new BigNumber(currentBlockTimestamp - tenMinutesInSeconds * 2);
auctionEndTimeSeconds = new BigNumber(currentBlockTimestamp - tenMinutesInSeconds);
+ const makerAssetData = DutchAuctionWrapper.encodeDutchAuctionAssetData(
+ defaultERC20MakerAssetData,
+ auctionBeginTimeSeconds,
+ auctionBeginAmount,
+ );
sellOrder = await sellerOrderFactory.newSignedOrderAsync({
- makerAssetData: extendMakerAssetData(
- assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress),
- auctionBeginTimeSeconds,
- auctionBeginAmount,
- ),
+ makerAssetData,
expirationTimeSeconds: auctionEndTimeSeconds,
});
- const auctionDetails = await dutchAuctionContract.getAuctionDetails.callAsync(sellOrder);
+ const auctionDetails = await dutchAuctionTestWrapper.getAuctionDetailsAsync(sellOrder);
+ expect(auctionDetails.currentTimeSeconds).to.be.bignumber.gte(auctionEndTimeSeconds);
expect(auctionDetails.currentAmount).to.be.bignumber.equal(auctionEndAmount);
expect(auctionDetails.beginAmount).to.be.bignumber.equal(auctionBeginAmount);
});
it('should match orders at current amount and send excess to buyer', async () => {
- const beforeAuctionDetails = await dutchAuctionContract.getAuctionDetails.callAsync(sellOrder);
+ const beforeAuctionDetails = await dutchAuctionTestWrapper.getAuctionDetailsAsync(sellOrder);
buyOrder = await buyerOrderFactory.newSignedOrderAsync({
makerAssetAmount: beforeAuctionDetails.currentAmount.times(2),
});
- await web3Wrapper.awaitTransactionSuccessAsync(
- await dutchAuctionContract.matchOrders.sendTransactionAsync(
- buyOrder,
- sellOrder,
- buyOrder.signature,
- sellOrder.signature,
- {
- from: takerAddress,
- },
- ),
- );
- const afterAuctionDetails = await dutchAuctionContract.getAuctionDetails.callAsync(sellOrder);
+ await dutchAuctionTestWrapper.matchOrdersAsync(buyOrder, sellOrder, takerAddress);
+ const afterAuctionDetails = await dutchAuctionTestWrapper.getAuctionDetailsAsync(sellOrder);
const newBalances = await erc20Wrapper.getBalancesAsync();
expect(newBalances[dutchAuctionContract.address][wethContract.address]).to.be.bignumber.equal(
constants.ZERO_AMOUNT,
@@ -276,17 +259,8 @@ describe(ContractName.DutchAuction, () => {
sellOrder = await sellerOrderFactory.newSignedOrderAsync({
makerFee: new BigNumber(1),
});
- const txHash = await dutchAuctionContract.matchOrders.sendTransactionAsync(
- buyOrder,
- sellOrder,
- buyOrder.signature,
- sellOrder.signature,
- {
- from: takerAddress,
- },
- );
- await web3Wrapper.awaitTransactionSuccessAsync(txHash);
- const afterAuctionDetails = await dutchAuctionContract.getAuctionDetails.callAsync(sellOrder);
+ await dutchAuctionTestWrapper.matchOrdersAsync(buyOrder, sellOrder, takerAddress);
+ const afterAuctionDetails = await dutchAuctionTestWrapper.getAuctionDetailsAsync(sellOrder);
const newBalances = await erc20Wrapper.getBalancesAsync();
expect(newBalances[makerAddress][wethContract.address]).to.be.bignumber.gte(
erc20Balances[makerAddress][wethContract.address].plus(afterAuctionDetails.currentAmount),
@@ -299,18 +273,9 @@ describe(ContractName.DutchAuction, () => {
buyOrder = await buyerOrderFactory.newSignedOrderAsync({
makerFee: new BigNumber(1),
});
- const txHash = await dutchAuctionContract.matchOrders.sendTransactionAsync(
- buyOrder,
- sellOrder,
- buyOrder.signature,
- sellOrder.signature,
- {
- from: takerAddress,
- },
- );
- await web3Wrapper.awaitTransactionSuccessAsync(txHash);
+ await dutchAuctionTestWrapper.matchOrdersAsync(buyOrder, sellOrder, takerAddress);
const newBalances = await erc20Wrapper.getBalancesAsync();
- const afterAuctionDetails = await dutchAuctionContract.getAuctionDetails.callAsync(sellOrder);
+ const afterAuctionDetails = await dutchAuctionTestWrapper.getAuctionDetailsAsync(sellOrder);
expect(newBalances[makerAddress][wethContract.address]).to.be.bignumber.gte(
erc20Balances[makerAddress][wethContract.address].plus(afterAuctionDetails.currentAmount),
);
@@ -321,24 +286,17 @@ describe(ContractName.DutchAuction, () => {
it('should revert when auction expires', async () => {
auctionBeginTimeSeconds = new BigNumber(currentBlockTimestamp - tenMinutesInSeconds * 2);
auctionEndTimeSeconds = new BigNumber(currentBlockTimestamp - tenMinutesInSeconds);
+ const makerAssetData = DutchAuctionWrapper.encodeDutchAuctionAssetData(
+ defaultERC20MakerAssetData,
+ auctionBeginTimeSeconds,
+ auctionBeginAmount,
+ );
sellOrder = await sellerOrderFactory.newSignedOrderAsync({
expirationTimeSeconds: auctionEndTimeSeconds,
- makerAssetData: extendMakerAssetData(
- assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress),
- auctionBeginTimeSeconds,
- auctionBeginAmount,
- ),
+ makerAssetData,
});
return expectTransactionFailedAsync(
- dutchAuctionContract.matchOrders.sendTransactionAsync(
- buyOrder,
- sellOrder,
- buyOrder.signature,
- sellOrder.signature,
- {
- from: takerAddress,
- },
- ),
+ dutchAuctionTestWrapper.matchOrdersAsync(buyOrder, sellOrder, takerAddress),
RevertReason.AuctionExpired,
);
});
@@ -347,15 +305,7 @@ describe(ContractName.DutchAuction, () => {
makerAssetAmount: sellOrder.takerAssetAmount,
});
return expectTransactionFailedAsync(
- dutchAuctionContract.matchOrders.sendTransactionAsync(
- buyOrder,
- sellOrder,
- buyOrder.signature,
- sellOrder.signature,
- {
- from: takerAddress,
- },
- ),
+ dutchAuctionTestWrapper.matchOrdersAsync(buyOrder, sellOrder, takerAddress),
RevertReason.AuctionInvalidAmount,
);
});
@@ -364,38 +314,23 @@ describe(ContractName.DutchAuction, () => {
takerAssetAmount: auctionBeginAmount.plus(1),
});
return expectTransactionFailedAsync(
- dutchAuctionContract.matchOrders.sendTransactionAsync(
- buyOrder,
- sellOrder,
- buyOrder.signature,
- sellOrder.signature,
- {
- from: takerAddress,
- },
- ),
+ dutchAuctionTestWrapper.matchOrdersAsync(buyOrder, sellOrder, takerAddress),
RevertReason.AuctionInvalidAmount,
);
});
it('begin time is less than end time', async () => {
auctionBeginTimeSeconds = new BigNumber(auctionEndTimeSeconds).plus(tenMinutesInSeconds);
+ const makerAssetData = DutchAuctionWrapper.encodeDutchAuctionAssetData(
+ defaultERC20MakerAssetData,
+ auctionBeginTimeSeconds,
+ auctionBeginAmount,
+ );
sellOrder = await sellerOrderFactory.newSignedOrderAsync({
expirationTimeSeconds: auctionEndTimeSeconds,
- makerAssetData: extendMakerAssetData(
- assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress),
- auctionBeginTimeSeconds,
- auctionBeginAmount,
- ),
+ makerAssetData,
});
return expectTransactionFailedAsync(
- dutchAuctionContract.matchOrders.sendTransactionAsync(
- buyOrder,
- sellOrder,
- buyOrder.signature,
- sellOrder.signature,
- {
- from: takerAddress,
- },
- ),
+ dutchAuctionTestWrapper.matchOrdersAsync(buyOrder, sellOrder, takerAddress),
RevertReason.AuctionInvalidBeginTime,
);
});
@@ -404,45 +339,30 @@ describe(ContractName.DutchAuction, () => {
makerAssetData: assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress),
});
return expectTransactionFailedAsync(
- dutchAuctionContract.matchOrders.sendTransactionAsync(
- buyOrder,
- sellOrder,
- buyOrder.signature,
- sellOrder.signature,
- {
- from: takerAddress,
- },
- ),
+ dutchAuctionTestWrapper.matchOrdersAsync(buyOrder, sellOrder, takerAddress),
RevertReason.InvalidAssetData,
);
});
+
describe('ERC721', () => {
it('should match orders when ERC721', async () => {
const makerAssetId = erc721MakerAssetIds[0];
+ const erc721MakerAssetData = assetDataUtils.encodeERC721AssetData(erc721Token.address, makerAssetId);
+ const makerAssetData = DutchAuctionWrapper.encodeDutchAuctionAssetData(
+ erc721MakerAssetData,
+ auctionBeginTimeSeconds,
+ auctionBeginAmount,
+ );
sellOrder = await sellerOrderFactory.newSignedOrderAsync({
makerAssetAmount: new BigNumber(1),
- makerAssetData: extendMakerAssetData(
- assetDataUtils.encodeERC721AssetData(erc721Token.address, makerAssetId),
- auctionBeginTimeSeconds,
- auctionBeginAmount,
- ),
+ makerAssetData,
});
buyOrder = await buyerOrderFactory.newSignedOrderAsync({
takerAssetAmount: new BigNumber(1),
takerAssetData: sellOrder.makerAssetData,
});
- await web3Wrapper.awaitTransactionSuccessAsync(
- await dutchAuctionContract.matchOrders.sendTransactionAsync(
- buyOrder,
- sellOrder,
- buyOrder.signature,
- sellOrder.signature,
- {
- from: takerAddress,
- },
- ),
- );
- const afterAuctionDetails = await dutchAuctionContract.getAuctionDetails.callAsync(sellOrder);
+ await dutchAuctionTestWrapper.matchOrdersAsync(buyOrder, sellOrder, takerAddress);
+ const afterAuctionDetails = await dutchAuctionTestWrapper.getAuctionDetailsAsync(sellOrder);
const newBalances = await erc20Wrapper.getBalancesAsync();
// HACK gte used here due to a bug in ganache where the timestamp can change
// between multiple calls to the same block. Which can move the amount in our case
diff --git a/contracts/extensions/test/extensions/forwarder.ts b/contracts/extensions/test/extensions/forwarder.ts
index 4027f493d..69939ed04 100644
--- a/contracts/extensions/test/extensions/forwarder.ts
+++ b/contracts/extensions/test/extensions/forwarder.ts
@@ -48,7 +48,6 @@ describe(ContractName.Forwarder, () => {
let owner: string;
let takerAddress: string;
let feeRecipientAddress: string;
- let otherAddress: string;
let defaultMakerAssetAddress: string;
let zrxAssetData: string;
let wethAssetData: string;
@@ -78,7 +77,7 @@ describe(ContractName.Forwarder, () => {
before(async () => {
await blockchainLifecycle.startAsync();
const accounts = await web3Wrapper.getAvailableAddressesAsync();
- const usedAddresses = ([owner, makerAddress, takerAddress, feeRecipientAddress, otherAddress] = accounts);
+ const usedAddresses = ([owner, makerAddress, takerAddress, feeRecipientAddress] = accounts);
const txHash = await web3Wrapper.sendTransactionAsync({ from: accounts[0], to: accounts[0], value: 0 });
const transaction = await web3Wrapper.getTransactionByHashAsync(txHash);
diff --git a/contracts/extensions/test/extensions/order_matcher.ts b/contracts/extensions/test/extensions/order_matcher.ts
new file mode 100644
index 000000000..acb46ced4
--- /dev/null
+++ b/contracts/extensions/test/extensions/order_matcher.ts
@@ -0,0 +1,818 @@
+import {
+ artifacts as protocolArtifacts,
+ ERC20ProxyContract,
+ ERC20Wrapper,
+ ERC721ProxyContract,
+ ExchangeContract,
+ ExchangeFillEventArgs,
+ ExchangeWrapper,
+} from '@0x/contracts-protocol';
+import {
+ chaiSetup,
+ constants,
+ ERC20BalancesByOwner,
+ expectContractCreationFailedAsync,
+ expectTransactionFailedAsync,
+ LogDecoder,
+ OrderFactory,
+ provider,
+ sendTransactionResult,
+ txDefaults,
+ web3Wrapper,
+} from '@0x/contracts-test-utils';
+import { artifacts as tokenArtifacts, DummyERC20TokenContract, DummyERC721TokenContract } from '@0x/contracts-tokens';
+import { BlockchainLifecycle } from '@0x/dev-utils';
+import { assetDataUtils } from '@0x/order-utils';
+import { RevertReason } from '@0x/types';
+import { BigNumber } from '@0x/utils';
+import { Web3Wrapper } from '@0x/web3-wrapper';
+import * as chai from 'chai';
+import { LogWithDecodedArgs } from 'ethereum-types';
+import * as _ from 'lodash';
+
+import { OrderMatcherContract } from '../../generated-wrappers/order_matcher';
+import { artifacts } from '../../src/artifacts';
+
+const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
+chaiSetup.configure();
+const expect = chai.expect;
+// tslint:disable:no-unnecessary-type-assertion
+describe('OrderMatcher', () => {
+ let makerAddressLeft: string;
+ let makerAddressRight: string;
+ let owner: string;
+ let takerAddress: string;
+ let feeRecipientAddressLeft: string;
+ let feeRecipientAddressRight: string;
+
+ let erc20TokenA: DummyERC20TokenContract;
+ let erc20TokenB: DummyERC20TokenContract;
+ let zrxToken: DummyERC20TokenContract;
+ let exchange: ExchangeContract;
+ let erc20Proxy: ERC20ProxyContract;
+ let erc721Proxy: ERC721ProxyContract;
+ let orderMatcher: OrderMatcherContract;
+
+ let erc20BalancesByOwner: ERC20BalancesByOwner;
+ let exchangeWrapper: ExchangeWrapper;
+ let erc20Wrapper: ERC20Wrapper;
+ let orderFactoryLeft: OrderFactory;
+ let orderFactoryRight: OrderFactory;
+
+ let leftMakerAssetData: string;
+ let leftTakerAssetData: string;
+ let defaultERC20MakerAssetAddress: string;
+ let defaultERC20TakerAssetAddress: string;
+
+ before(async () => {
+ await blockchainLifecycle.startAsync();
+ });
+ after(async () => {
+ await blockchainLifecycle.revertAsync();
+ });
+ before(async () => {
+ // Create accounts
+ const accounts = await web3Wrapper.getAvailableAddressesAsync();
+ // Hack(albrow): Both Prettier and TSLint insert a trailing comma below
+ // but that is invalid syntax as of TypeScript version >= 2.8. We don't
+ // have the right fine-grained configuration options in TSLint,
+ // Prettier, or TypeScript, to reconcile this, so we will just have to
+ // wait for them to sort it out. We disable TSLint and Prettier for
+ // this part of the code for now. This occurs several times in this
+ // file. See https://github.com/prettier/prettier/issues/4624.
+ // prettier-ignore
+ const usedAddresses = ([
+ owner,
+ makerAddressLeft,
+ makerAddressRight,
+ takerAddress,
+ feeRecipientAddressLeft,
+ // tslint:disable-next-line:trailing-comma
+ feeRecipientAddressRight
+ ] = _.slice(accounts, 0, 6));
+ // Create wrappers
+ erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner);
+ // Deploy ERC20 token & ERC20 proxy
+ const numDummyErc20ToDeploy = 3;
+ [erc20TokenA, erc20TokenB, zrxToken] = await erc20Wrapper.deployDummyTokensAsync(
+ numDummyErc20ToDeploy,
+ constants.DUMMY_TOKEN_DECIMALS,
+ );
+ erc20Proxy = await erc20Wrapper.deployProxyAsync();
+ await erc20Wrapper.setBalancesAndAllowancesAsync();
+ // Deploy ERC721 proxy
+ erc721Proxy = await ERC721ProxyContract.deployFrom0xArtifactAsync(
+ protocolArtifacts.ERC721Proxy,
+ provider,
+ txDefaults,
+ );
+ // Depoy exchange
+ exchange = await ExchangeContract.deployFrom0xArtifactAsync(
+ protocolArtifacts.Exchange,
+ provider,
+ txDefaults,
+ assetDataUtils.encodeERC20AssetData(zrxToken.address),
+ );
+ exchangeWrapper = new ExchangeWrapper(exchange, provider);
+ await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner);
+ await exchangeWrapper.registerAssetProxyAsync(erc721Proxy.address, owner);
+ // Authorize ERC20 trades by exchange
+ await web3Wrapper.awaitTransactionSuccessAsync(
+ await erc20Proxy.addAuthorizedAddress.sendTransactionAsync(exchange.address, {
+ from: owner,
+ }),
+ constants.AWAIT_TRANSACTION_MINED_MS,
+ );
+ // Deploy OrderMatcher
+ orderMatcher = await OrderMatcherContract.deployFrom0xArtifactAsync(
+ artifacts.OrderMatcher,
+ provider,
+ txDefaults,
+ exchange.address,
+ );
+ // Set default addresses
+ defaultERC20MakerAssetAddress = erc20TokenA.address;
+ defaultERC20TakerAssetAddress = erc20TokenB.address;
+ leftMakerAssetData = assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress);
+ leftTakerAssetData = assetDataUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress);
+ // Set OrderMatcher balances and allowances
+ await web3Wrapper.awaitTransactionSuccessAsync(
+ await erc20TokenA.setBalance.sendTransactionAsync(orderMatcher.address, constants.INITIAL_ERC20_BALANCE, {
+ from: owner,
+ }),
+ constants.AWAIT_TRANSACTION_MINED_MS,
+ );
+ await web3Wrapper.awaitTransactionSuccessAsync(
+ await erc20TokenB.setBalance.sendTransactionAsync(orderMatcher.address, constants.INITIAL_ERC20_BALANCE, {
+ from: owner,
+ }),
+ constants.AWAIT_TRANSACTION_MINED_MS,
+ );
+ await web3Wrapper.awaitTransactionSuccessAsync(
+ await orderMatcher.approveAssetProxy.sendTransactionAsync(
+ leftMakerAssetData,
+ constants.INITIAL_ERC20_ALLOWANCE,
+ ),
+ constants.AWAIT_TRANSACTION_MINED_MS,
+ );
+ await web3Wrapper.awaitTransactionSuccessAsync(
+ await orderMatcher.approveAssetProxy.sendTransactionAsync(
+ leftTakerAssetData,
+ constants.INITIAL_ERC20_ALLOWANCE,
+ ),
+ constants.AWAIT_TRANSACTION_MINED_MS,
+ );
+ // Create default order parameters
+ const defaultOrderParamsLeft = {
+ ...constants.STATIC_ORDER_PARAMS,
+ makerAddress: makerAddressLeft,
+ exchangeAddress: exchange.address,
+ makerAssetData: leftMakerAssetData,
+ takerAssetData: leftTakerAssetData,
+ feeRecipientAddress: feeRecipientAddressLeft,
+ makerFee: constants.ZERO_AMOUNT,
+ takerFee: constants.ZERO_AMOUNT,
+ };
+ const defaultOrderParamsRight = {
+ ...constants.STATIC_ORDER_PARAMS,
+ makerAddress: makerAddressRight,
+ exchangeAddress: exchange.address,
+ makerAssetData: leftTakerAssetData,
+ takerAssetData: leftMakerAssetData,
+ feeRecipientAddress: feeRecipientAddressRight,
+ makerFee: constants.ZERO_AMOUNT,
+ takerFee: constants.ZERO_AMOUNT,
+ };
+ const privateKeyLeft = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddressLeft)];
+ orderFactoryLeft = new OrderFactory(privateKeyLeft, defaultOrderParamsLeft);
+ const privateKeyRight = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddressRight)];
+ orderFactoryRight = new OrderFactory(privateKeyRight, defaultOrderParamsRight);
+ });
+ beforeEach(async () => {
+ await blockchainLifecycle.startAsync();
+ });
+ afterEach(async () => {
+ await blockchainLifecycle.revertAsync();
+ });
+ describe('constructor', () => {
+ it('should revert if assetProxy is unregistered', async () => {
+ const exchangeInstance = await ExchangeContract.deployFrom0xArtifactAsync(
+ protocolArtifacts.Exchange,
+ provider,
+ txDefaults,
+ constants.NULL_BYTES,
+ );
+ return expectContractCreationFailedAsync(
+ (OrderMatcherContract.deployFrom0xArtifactAsync(
+ artifacts.OrderMatcher,
+ provider,
+ txDefaults,
+ exchangeInstance.address,
+ ) as any) as sendTransactionResult,
+ RevertReason.UnregisteredAssetProxy,
+ );
+ });
+ });
+ describe('matchOrders', () => {
+ beforeEach(async () => {
+ erc20BalancesByOwner = await erc20Wrapper.getBalancesAsync();
+ });
+ it('should revert if not called by owner', async () => {
+ // Create orders to match
+ const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
+ makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
+ takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
+ });
+ const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
+ makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
+ takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
+ });
+ const data = exchange.matchOrders.getABIEncodedTransactionData(
+ signedOrderLeft,
+ signedOrderRight,
+ signedOrderLeft.signature,
+ signedOrderRight.signature,
+ );
+ await expectTransactionFailedAsync(
+ web3Wrapper.sendTransactionAsync({
+ data,
+ to: orderMatcher.address,
+ from: takerAddress,
+ gas: constants.MAX_MATCH_ORDERS_GAS,
+ }),
+ RevertReason.OnlyContractOwner,
+ );
+ });
+ it('should transfer the correct amounts when orders completely fill each other', async () => {
+ // Create orders to match
+ const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
+ makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
+ takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
+ });
+ const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
+ makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
+ takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
+ });
+ // Match signedOrderLeft with signedOrderRight
+ const expectedTransferAmounts = {
+ // Left Maker
+ amountSoldByLeftMaker: signedOrderLeft.makerAssetAmount,
+ amountBoughtByLeftMaker: signedOrderLeft.takerAssetAmount,
+ // Right Maker
+ amountSoldByRightMaker: signedOrderRight.makerAssetAmount,
+ amountBoughtByRightMaker: signedOrderRight.takerAssetAmount,
+ // Taker
+ leftMakerAssetSpreadAmount: signedOrderLeft.makerAssetAmount.minus(signedOrderRight.takerAssetAmount),
+ };
+ const initialLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
+ const data = exchange.matchOrders.getABIEncodedTransactionData(
+ signedOrderLeft,
+ signedOrderRight,
+ signedOrderLeft.signature,
+ signedOrderRight.signature,
+ );
+ await web3Wrapper.awaitTransactionSuccessAsync(
+ await web3Wrapper.sendTransactionAsync({
+ data,
+ to: orderMatcher.address,
+ from: owner,
+ gas: constants.MAX_MATCH_ORDERS_GAS,
+ }),
+ constants.AWAIT_TRANSACTION_MINED_MS,
+ );
+ const newLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
+ const newErc20Balances = await erc20Wrapper.getBalancesAsync();
+ expect(newErc20Balances[makerAddressLeft][defaultERC20MakerAssetAddress]).to.be.bignumber.equal(
+ erc20BalancesByOwner[makerAddressLeft][defaultERC20MakerAssetAddress].minus(
+ expectedTransferAmounts.amountSoldByLeftMaker,
+ ),
+ );
+ expect(newErc20Balances[makerAddressRight][defaultERC20TakerAssetAddress]).to.be.bignumber.equal(
+ erc20BalancesByOwner[makerAddressRight][defaultERC20TakerAssetAddress].minus(
+ expectedTransferAmounts.amountSoldByRightMaker,
+ ),
+ );
+ expect(newErc20Balances[makerAddressLeft][defaultERC20TakerAssetAddress]).to.be.bignumber.equal(
+ erc20BalancesByOwner[makerAddressLeft][defaultERC20TakerAssetAddress].plus(
+ expectedTransferAmounts.amountBoughtByLeftMaker,
+ ),
+ );
+ expect(newErc20Balances[makerAddressRight][defaultERC20MakerAssetAddress]).to.be.bignumber.equal(
+ erc20BalancesByOwner[makerAddressRight][defaultERC20MakerAssetAddress].plus(
+ expectedTransferAmounts.amountBoughtByRightMaker,
+ ),
+ );
+ expect(newLeftMakerAssetTakerBalance).to.be.bignumber.equal(
+ initialLeftMakerAssetTakerBalance.plus(expectedTransferAmounts.leftMakerAssetSpreadAmount),
+ );
+ });
+ it('should transfer the correct amounts when orders completely fill each other and taker doesnt take a profit', async () => {
+ // Create orders to match
+ const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
+ makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
+ takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
+ });
+ const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
+ makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
+ takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
+ });
+ // Match signedOrderLeft with signedOrderRight
+ const expectedTransferAmounts = {
+ // Left Maker
+ amountSoldByLeftMaker: signedOrderLeft.makerAssetAmount,
+ amountBoughtByLeftMaker: signedOrderLeft.takerAssetAmount,
+ // Right Maker
+ amountSoldByRightMaker: signedOrderRight.makerAssetAmount,
+ amountBoughtByRightMaker: signedOrderRight.takerAssetAmount,
+ };
+ const initialLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
+ const data = exchange.matchOrders.getABIEncodedTransactionData(
+ signedOrderLeft,
+ signedOrderRight,
+ signedOrderLeft.signature,
+ signedOrderRight.signature,
+ );
+ await web3Wrapper.awaitTransactionSuccessAsync(
+ await web3Wrapper.sendTransactionAsync({
+ data,
+ to: orderMatcher.address,
+ from: owner,
+ gas: constants.MAX_MATCH_ORDERS_GAS,
+ }),
+ constants.AWAIT_TRANSACTION_MINED_MS,
+ );
+ const newLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
+ const newErc20Balances = await erc20Wrapper.getBalancesAsync();
+ expect(newErc20Balances[makerAddressLeft][defaultERC20MakerAssetAddress]).to.be.bignumber.equal(
+ erc20BalancesByOwner[makerAddressLeft][defaultERC20MakerAssetAddress].minus(
+ expectedTransferAmounts.amountSoldByLeftMaker,
+ ),
+ );
+ expect(newErc20Balances[makerAddressRight][defaultERC20TakerAssetAddress]).to.be.bignumber.equal(
+ erc20BalancesByOwner[makerAddressRight][defaultERC20TakerAssetAddress].minus(
+ expectedTransferAmounts.amountSoldByRightMaker,
+ ),
+ );
+ expect(newErc20Balances[makerAddressLeft][defaultERC20TakerAssetAddress]).to.be.bignumber.equal(
+ erc20BalancesByOwner[makerAddressLeft][defaultERC20TakerAssetAddress].plus(
+ expectedTransferAmounts.amountBoughtByLeftMaker,
+ ),
+ );
+ expect(newErc20Balances[makerAddressRight][defaultERC20MakerAssetAddress]).to.be.bignumber.equal(
+ erc20BalancesByOwner[makerAddressRight][defaultERC20MakerAssetAddress].plus(
+ expectedTransferAmounts.amountBoughtByRightMaker,
+ ),
+ );
+ expect(newLeftMakerAssetTakerBalance).to.be.bignumber.equal(initialLeftMakerAssetTakerBalance);
+ });
+ it('should transfer the correct amounts when left order is completely filled and right order would be partially filled', async () => {
+ // Create orders to match
+ const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
+ makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
+ takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
+ });
+ const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
+ makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(20), 18),
+ takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(4), 18),
+ });
+ // Match signedOrderLeft with signedOrderRight
+ const expectedTransferAmounts = {
+ // Left Maker
+ amountSoldByLeftMaker: signedOrderLeft.makerAssetAmount,
+ amountBoughtByLeftMaker: signedOrderLeft.takerAssetAmount,
+ // Right Maker
+ amountSoldByRightMaker: signedOrderRight.makerAssetAmount,
+ amountBoughtByRightMaker: signedOrderRight.takerAssetAmount,
+ // Taker
+ leftMakerAssetSpreadAmount: signedOrderLeft.makerAssetAmount.minus(signedOrderRight.takerAssetAmount),
+ leftTakerAssetSpreadAmount: signedOrderRight.makerAssetAmount.minus(signedOrderLeft.takerAssetAmount),
+ };
+ const initialLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
+ const initialLeftTakerAssetTakerBalance = await erc20TokenB.balanceOf.callAsync(orderMatcher.address);
+ // Match signedOrderLeft with signedOrderRight
+ const data = exchange.matchOrders.getABIEncodedTransactionData(
+ signedOrderLeft,
+ signedOrderRight,
+ signedOrderLeft.signature,
+ signedOrderRight.signature,
+ );
+ await web3Wrapper.awaitTransactionSuccessAsync(
+ await web3Wrapper.sendTransactionAsync({
+ data,
+ to: orderMatcher.address,
+ from: owner,
+ gas: constants.MAX_MATCH_ORDERS_GAS,
+ }),
+ constants.AWAIT_TRANSACTION_MINED_MS,
+ );
+ const newLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
+ const newLeftTakerAssetTakerBalance = await erc20TokenB.balanceOf.callAsync(orderMatcher.address);
+ const newErc20Balances = await erc20Wrapper.getBalancesAsync();
+ expect(newErc20Balances[makerAddressLeft][defaultERC20MakerAssetAddress]).to.be.bignumber.equal(
+ erc20BalancesByOwner[makerAddressLeft][defaultERC20MakerAssetAddress].minus(
+ expectedTransferAmounts.amountSoldByLeftMaker,
+ ),
+ );
+ expect(newErc20Balances[makerAddressRight][defaultERC20TakerAssetAddress]).to.be.bignumber.equal(
+ erc20BalancesByOwner[makerAddressRight][defaultERC20TakerAssetAddress].minus(
+ expectedTransferAmounts.amountSoldByRightMaker,
+ ),
+ );
+ expect(newErc20Balances[makerAddressLeft][defaultERC20TakerAssetAddress]).to.be.bignumber.equal(
+ erc20BalancesByOwner[makerAddressLeft][defaultERC20TakerAssetAddress].plus(
+ expectedTransferAmounts.amountBoughtByLeftMaker,
+ ),
+ );
+ expect(newErc20Balances[makerAddressRight][defaultERC20MakerAssetAddress]).to.be.bignumber.equal(
+ erc20BalancesByOwner[makerAddressRight][defaultERC20MakerAssetAddress].plus(
+ expectedTransferAmounts.amountBoughtByRightMaker,
+ ),
+ );
+ expect(newLeftMakerAssetTakerBalance).to.be.bignumber.equal(
+ initialLeftMakerAssetTakerBalance.plus(expectedTransferAmounts.leftMakerAssetSpreadAmount),
+ );
+ expect(newLeftTakerAssetTakerBalance).to.be.bignumber.equal(
+ initialLeftTakerAssetTakerBalance.plus(expectedTransferAmounts.leftTakerAssetSpreadAmount),
+ );
+ });
+ it('should not call fillOrder when rightOrder is completely filled after matchOrders call and orders were never partially filled', async () => {
+ // Create orders to match
+ const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
+ makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
+ takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
+ });
+ const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
+ makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
+ takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
+ });
+ const data = exchange.matchOrders.getABIEncodedTransactionData(
+ signedOrderLeft,
+ signedOrderRight,
+ signedOrderLeft.signature,
+ signedOrderRight.signature,
+ );
+ const logDecoder = new LogDecoder(web3Wrapper, { ...artifacts, ...tokenArtifacts, ...protocolArtifacts });
+ const txReceipt = await logDecoder.getTxWithDecodedLogsAsync(
+ await web3Wrapper.sendTransactionAsync({
+ data,
+ to: orderMatcher.address,
+ from: owner,
+ gas: constants.MAX_MATCH_ORDERS_GAS,
+ }),
+ );
+ const fillLogs = _.filter(
+ txReceipt.logs,
+ log => (log as LogWithDecodedArgs<ExchangeFillEventArgs>).event === 'Fill',
+ );
+ // Only 2 Fill logs should exist for `matchOrders` call. `fillOrder` should not have been called and should not have emitted a Fill event.
+ expect(fillLogs.length).to.be.equal(2);
+ });
+ it('should not call fillOrder when rightOrder is completely filled after matchOrders call and orders were initially partially filled', async () => {
+ // Create orders to match
+ const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
+ makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
+ takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
+ });
+ const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
+ makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
+ takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
+ });
+ await exchangeWrapper.fillOrderAsync(signedOrderLeft, takerAddress, {
+ takerAssetFillAmount: signedOrderLeft.takerAssetAmount.dividedToIntegerBy(5),
+ });
+ await exchangeWrapper.fillOrderAsync(signedOrderRight, takerAddress, {
+ takerAssetFillAmount: signedOrderRight.takerAssetAmount.dividedToIntegerBy(5),
+ });
+ const data = exchange.matchOrders.getABIEncodedTransactionData(
+ signedOrderLeft,
+ signedOrderRight,
+ signedOrderLeft.signature,
+ signedOrderRight.signature,
+ );
+ const logDecoder = new LogDecoder(web3Wrapper, { ...artifacts, ...tokenArtifacts, ...protocolArtifacts });
+ const txReceipt = await logDecoder.getTxWithDecodedLogsAsync(
+ await web3Wrapper.sendTransactionAsync({
+ data,
+ to: orderMatcher.address,
+ from: owner,
+ gas: constants.MAX_MATCH_ORDERS_GAS,
+ }),
+ );
+ const fillLogs = _.filter(
+ txReceipt.logs,
+ log => (log as LogWithDecodedArgs<ExchangeFillEventArgs>).event === 'Fill',
+ );
+ // Only 2 Fill logs should exist for `matchOrders` call. `fillOrder` should not have been called and should not have emitted a Fill event.
+ expect(fillLogs.length).to.be.equal(2);
+ });
+ it('should only take a spread in rightMakerAsset if entire leftMakerAssetSpread amount can be used to fill rightOrder after matchOrders call', async () => {
+ // Create orders to match
+ const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
+ makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
+ takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(0.9), 18),
+ });
+ const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
+ makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18),
+ takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(990), 18),
+ });
+ const initialLeftMakerAssetSpreadAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(1.09), 18);
+ const leftTakerAssetSpreadAmount = initialLeftMakerAssetSpreadAmount
+ .times(signedOrderRight.makerAssetAmount)
+ .dividedToIntegerBy(signedOrderRight.takerAssetAmount);
+ // Match signedOrderLeft with signedOrderRight
+ const expectedTransferAmounts = {
+ // Left Maker
+ amountSoldByLeftMaker: signedOrderLeft.makerAssetAmount,
+ amountBoughtByLeftMaker: signedOrderLeft.takerAssetAmount,
+ // Right Maker
+ amountSoldByRightMaker: signedOrderLeft.takerAssetAmount.plus(leftTakerAssetSpreadAmount),
+ amountBoughtByRightMaker: signedOrderLeft.makerAssetAmount,
+ // Taker
+ leftMakerAssetSpreadAmount: constants.ZERO_AMOUNT,
+ leftTakerAssetSpreadAmount,
+ };
+ const initialLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
+ const initialLeftTakerAssetTakerBalance = await erc20TokenB.balanceOf.callAsync(orderMatcher.address);
+ // Match signedOrderLeft with signedOrderRight
+ const data = exchange.matchOrders.getABIEncodedTransactionData(
+ signedOrderLeft,
+ signedOrderRight,
+ signedOrderLeft.signature,
+ signedOrderRight.signature,
+ );
+ await web3Wrapper.awaitTransactionSuccessAsync(
+ await web3Wrapper.sendTransactionAsync({
+ data,
+ to: orderMatcher.address,
+ from: owner,
+ gas: constants.MAX_MATCH_ORDERS_GAS,
+ }),
+ constants.AWAIT_TRANSACTION_MINED_MS,
+ );
+ const newLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
+ const newLeftTakerAssetTakerBalance = await erc20TokenB.balanceOf.callAsync(orderMatcher.address);
+ const newErc20Balances = await erc20Wrapper.getBalancesAsync();
+ expect(newErc20Balances[makerAddressLeft][defaultERC20MakerAssetAddress]).to.be.bignumber.equal(
+ erc20BalancesByOwner[makerAddressLeft][defaultERC20MakerAssetAddress].minus(
+ expectedTransferAmounts.amountSoldByLeftMaker,
+ ),
+ );
+ expect(newErc20Balances[makerAddressRight][defaultERC20TakerAssetAddress]).to.be.bignumber.equal(
+ erc20BalancesByOwner[makerAddressRight][defaultERC20TakerAssetAddress].minus(
+ expectedTransferAmounts.amountSoldByRightMaker,
+ ),
+ );
+ expect(newErc20Balances[makerAddressLeft][defaultERC20TakerAssetAddress]).to.be.bignumber.equal(
+ erc20BalancesByOwner[makerAddressLeft][defaultERC20TakerAssetAddress].plus(
+ expectedTransferAmounts.amountBoughtByLeftMaker,
+ ),
+ );
+ expect(newErc20Balances[makerAddressRight][defaultERC20MakerAssetAddress]).to.be.bignumber.equal(
+ erc20BalancesByOwner[makerAddressRight][defaultERC20MakerAssetAddress].plus(
+ expectedTransferAmounts.amountBoughtByRightMaker,
+ ),
+ );
+ expect(newLeftMakerAssetTakerBalance).to.be.bignumber.equal(
+ initialLeftMakerAssetTakerBalance.plus(expectedTransferAmounts.leftMakerAssetSpreadAmount),
+ );
+ expect(newLeftTakerAssetTakerBalance).to.be.bignumber.equal(
+ initialLeftTakerAssetTakerBalance.plus(expectedTransferAmounts.leftTakerAssetSpreadAmount),
+ );
+ });
+ it("should succeed if rightOrder's makerAssetData and takerAssetData are not provided", async () => {
+ // Create orders to match
+ const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
+ makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
+ takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
+ });
+ const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
+ makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(20), 18),
+ takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(4), 18),
+ });
+ // Match signedOrderLeft with signedOrderRight
+ const expectedTransferAmounts = {
+ // Left Maker
+ amountSoldByLeftMaker: signedOrderLeft.makerAssetAmount,
+ amountBoughtByLeftMaker: signedOrderLeft.takerAssetAmount,
+ // Right Maker
+ amountSoldByRightMaker: signedOrderRight.makerAssetAmount,
+ amountBoughtByRightMaker: signedOrderRight.takerAssetAmount,
+ // Taker
+ leftMakerAssetSpreadAmount: signedOrderLeft.makerAssetAmount.minus(signedOrderRight.takerAssetAmount),
+ leftTakerAssetSpreadAmount: signedOrderRight.makerAssetAmount.minus(signedOrderLeft.takerAssetAmount),
+ };
+ const initialLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
+ const initialLeftTakerAssetTakerBalance = await erc20TokenB.balanceOf.callAsync(orderMatcher.address);
+ // Match signedOrderLeft with signedOrderRight
+ signedOrderRight.makerAssetData = constants.NULL_BYTES;
+ signedOrderRight.takerAssetData = constants.NULL_BYTES;
+ const data = exchange.matchOrders.getABIEncodedTransactionData(
+ signedOrderLeft,
+ signedOrderRight,
+ signedOrderLeft.signature,
+ signedOrderRight.signature,
+ );
+ await web3Wrapper.awaitTransactionSuccessAsync(
+ await web3Wrapper.sendTransactionAsync({
+ data,
+ to: orderMatcher.address,
+ from: owner,
+ gas: constants.MAX_MATCH_ORDERS_GAS,
+ }),
+ constants.AWAIT_TRANSACTION_MINED_MS,
+ );
+ const newLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
+ const newLeftTakerAssetTakerBalance = await erc20TokenB.balanceOf.callAsync(orderMatcher.address);
+ const newErc20Balances = await erc20Wrapper.getBalancesAsync();
+ expect(newErc20Balances[makerAddressLeft][defaultERC20MakerAssetAddress]).to.be.bignumber.equal(
+ erc20BalancesByOwner[makerAddressLeft][defaultERC20MakerAssetAddress].minus(
+ expectedTransferAmounts.amountSoldByLeftMaker,
+ ),
+ );
+ expect(newErc20Balances[makerAddressRight][defaultERC20TakerAssetAddress]).to.be.bignumber.equal(
+ erc20BalancesByOwner[makerAddressRight][defaultERC20TakerAssetAddress].minus(
+ expectedTransferAmounts.amountSoldByRightMaker,
+ ),
+ );
+ expect(newErc20Balances[makerAddressLeft][defaultERC20TakerAssetAddress]).to.be.bignumber.equal(
+ erc20BalancesByOwner[makerAddressLeft][defaultERC20TakerAssetAddress].plus(
+ expectedTransferAmounts.amountBoughtByLeftMaker,
+ ),
+ );
+ expect(newErc20Balances[makerAddressRight][defaultERC20MakerAssetAddress]).to.be.bignumber.equal(
+ erc20BalancesByOwner[makerAddressRight][defaultERC20MakerAssetAddress].plus(
+ expectedTransferAmounts.amountBoughtByRightMaker,
+ ),
+ );
+ expect(newLeftMakerAssetTakerBalance).to.be.bignumber.equal(
+ initialLeftMakerAssetTakerBalance.plus(expectedTransferAmounts.leftMakerAssetSpreadAmount),
+ );
+ expect(newLeftTakerAssetTakerBalance).to.be.bignumber.equal(
+ initialLeftTakerAssetTakerBalance.plus(expectedTransferAmounts.leftTakerAssetSpreadAmount),
+ );
+ });
+ it('should revert with the correct reason if matchOrders call reverts', async () => {
+ // Create orders to match
+ const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
+ makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
+ takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
+ });
+ const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
+ makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
+ takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
+ });
+ signedOrderRight.signature = `0xff${signedOrderRight.signature.slice(4)}`;
+ const data = exchange.matchOrders.getABIEncodedTransactionData(
+ signedOrderLeft,
+ signedOrderRight,
+ signedOrderLeft.signature,
+ signedOrderRight.signature,
+ );
+ await expectTransactionFailedAsync(
+ web3Wrapper.sendTransactionAsync({
+ data,
+ to: orderMatcher.address,
+ from: owner,
+ gas: constants.MAX_MATCH_ORDERS_GAS,
+ }),
+ RevertReason.InvalidOrderSignature,
+ );
+ });
+ it('should revert with the correct reason if fillOrder call reverts', async () => {
+ // Create orders to match
+ const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
+ makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
+ takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
+ });
+ const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
+ makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(20), 18),
+ takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(4), 18),
+ });
+ // Matcher will not have enough allowance to fill rightOrder
+ await web3Wrapper.awaitTransactionSuccessAsync(
+ await orderMatcher.approveAssetProxy.sendTransactionAsync(leftMakerAssetData, constants.ZERO_AMOUNT, {
+ from: owner,
+ }),
+ constants.AWAIT_TRANSACTION_MINED_MS,
+ );
+ const data = exchange.matchOrders.getABIEncodedTransactionData(
+ signedOrderLeft,
+ signedOrderRight,
+ signedOrderLeft.signature,
+ signedOrderRight.signature,
+ );
+ await expectTransactionFailedAsync(
+ web3Wrapper.sendTransactionAsync({
+ data,
+ to: orderMatcher.address,
+ from: owner,
+ gas: constants.MAX_MATCH_ORDERS_GAS,
+ }),
+ RevertReason.TransferFailed,
+ );
+ });
+ });
+ describe('withdrawAsset', () => {
+ it('should allow owner to withdraw ERC20 tokens', async () => {
+ const erc20AWithdrawAmount = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
+ expect(erc20AWithdrawAmount).to.be.bignumber.gt(constants.ZERO_AMOUNT);
+ await web3Wrapper.awaitTransactionSuccessAsync(
+ await orderMatcher.withdrawAsset.sendTransactionAsync(leftMakerAssetData, erc20AWithdrawAmount, {
+ from: owner,
+ }),
+ );
+ const newBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
+ expect(newBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ });
+ it('should allow owner to withdraw ERC721 tokens', async () => {
+ const erc721Token = await DummyERC721TokenContract.deployFrom0xArtifactAsync(
+ tokenArtifacts.DummyERC721Token,
+ provider,
+ txDefaults,
+ constants.DUMMY_TOKEN_NAME,
+ constants.DUMMY_TOKEN_SYMBOL,
+ );
+ const tokenId = new BigNumber(1);
+ await web3Wrapper.awaitTransactionSuccessAsync(
+ await erc721Token.mint.sendTransactionAsync(orderMatcher.address, tokenId, { from: owner }),
+ constants.AWAIT_TRANSACTION_MINED_MS,
+ );
+ const assetData = assetDataUtils.encodeERC721AssetData(erc721Token.address, tokenId);
+ const withdrawAmount = new BigNumber(1);
+ await web3Wrapper.awaitTransactionSuccessAsync(
+ await orderMatcher.withdrawAsset.sendTransactionAsync(assetData, withdrawAmount, { from: owner }),
+ constants.AWAIT_TRANSACTION_MINED_MS,
+ );
+ const erc721Owner = await erc721Token.ownerOf.callAsync(tokenId);
+ expect(erc721Owner).to.be.equal(owner);
+ });
+ it('should revert if not called by owner', async () => {
+ const erc20AWithdrawAmount = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
+ expect(erc20AWithdrawAmount).to.be.bignumber.gt(constants.ZERO_AMOUNT);
+ await expectTransactionFailedAsync(
+ orderMatcher.withdrawAsset.sendTransactionAsync(leftMakerAssetData, erc20AWithdrawAmount, {
+ from: takerAddress,
+ }),
+ RevertReason.OnlyContractOwner,
+ );
+ });
+ });
+ describe('approveAssetProxy', () => {
+ it('should be able to set an allowance for ERC20 tokens', async () => {
+ const allowance = new BigNumber(55465465426546);
+ await web3Wrapper.awaitTransactionSuccessAsync(
+ await orderMatcher.approveAssetProxy.sendTransactionAsync(leftMakerAssetData, allowance, {
+ from: owner,
+ }),
+ constants.AWAIT_TRANSACTION_MINED_MS,
+ );
+ const newAllowance = await erc20TokenA.allowance.callAsync(orderMatcher.address, erc20Proxy.address);
+ expect(newAllowance).to.be.bignumber.equal(allowance);
+ });
+ it('should be able to approve an ERC721 token by passing in allowance = 1', async () => {
+ const erc721Token = await DummyERC721TokenContract.deployFrom0xArtifactAsync(
+ tokenArtifacts.DummyERC721Token,
+ provider,
+ txDefaults,
+ constants.DUMMY_TOKEN_NAME,
+ constants.DUMMY_TOKEN_SYMBOL,
+ );
+ const assetData = assetDataUtils.encodeERC721AssetData(erc721Token.address, constants.ZERO_AMOUNT);
+ const allowance = new BigNumber(1);
+ await web3Wrapper.awaitTransactionSuccessAsync(
+ await orderMatcher.approveAssetProxy.sendTransactionAsync(assetData, allowance, { from: owner }),
+ constants.AWAIT_TRANSACTION_MINED_MS,
+ );
+ const isApproved = await erc721Token.isApprovedForAll.callAsync(orderMatcher.address, erc721Proxy.address);
+ expect(isApproved).to.be.equal(true);
+ });
+ it('should be able to approve an ERC721 token by passing in allowance > 1', async () => {
+ const erc721Token = await DummyERC721TokenContract.deployFrom0xArtifactAsync(
+ tokenArtifacts.DummyERC721Token,
+ provider,
+ txDefaults,
+ constants.DUMMY_TOKEN_NAME,
+ constants.DUMMY_TOKEN_SYMBOL,
+ );
+ const assetData = assetDataUtils.encodeERC721AssetData(erc721Token.address, constants.ZERO_AMOUNT);
+ const allowance = new BigNumber(2);
+ await web3Wrapper.awaitTransactionSuccessAsync(
+ await orderMatcher.approveAssetProxy.sendTransactionAsync(assetData, allowance, { from: owner }),
+ constants.AWAIT_TRANSACTION_MINED_MS,
+ );
+ const isApproved = await erc721Token.isApprovedForAll.callAsync(orderMatcher.address, erc721Proxy.address);
+ expect(isApproved).to.be.equal(true);
+ });
+ it('should revert if not called by owner', async () => {
+ const approval = new BigNumber(1);
+ await expectTransactionFailedAsync(
+ orderMatcher.approveAssetProxy.sendTransactionAsync(leftMakerAssetData, approval, {
+ from: takerAddress,
+ }),
+ RevertReason.OnlyContractOwner,
+ );
+ });
+ });
+});
+// tslint:disable:max-file-line-count
+// tslint:enable:no-unnecessary-type-assertion
diff --git a/contracts/protocol/test/exchange/order_validator.ts b/contracts/extensions/test/extensions/order_validator.ts
index 8f53426db..82a6b937f 100644
--- a/contracts/protocol/test/exchange/order_validator.ts
+++ b/contracts/extensions/test/extensions/order_validator.ts
@@ -1,4 +1,13 @@
import {
+ artifacts as protocolArtifacts,
+ ERC20ProxyContract,
+ ERC20Wrapper,
+ ERC721ProxyContract,
+ ERC721Wrapper,
+ ExchangeContract,
+ ExchangeWrapper,
+} from '@0x/contracts-protocol';
+import {
chaiSetup,
constants,
OrderFactory,
@@ -15,16 +24,8 @@ import { BigNumber } from '@0x/utils';
import * as chai from 'chai';
import * as _ from 'lodash';
-import {
- artifacts,
- ERC20ProxyContract,
- ERC20Wrapper,
- ERC721ProxyContract,
- ERC721Wrapper,
- ExchangeContract,
- ExchangeWrapper,
- OrderValidatorContract,
-} from '../../src';
+import { OrderValidatorContract } from '../../generated-wrappers/order_validator';
+import { artifacts } from '../../src/artifacts/index';
chaiSetup.configure();
const expect = chai.expect;
@@ -80,7 +81,7 @@ describe('OrderValidator', () => {
const zrxAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address);
exchange = await ExchangeContract.deployFrom0xArtifactAsync(
- artifacts.Exchange,
+ protocolArtifacts.Exchange,
provider,
txDefaults,
zrxAssetData,
diff --git a/contracts/extensions/test/utils/dutch_auction_test_wrapper.ts b/contracts/extensions/test/utils/dutch_auction_test_wrapper.ts
new file mode 100644
index 000000000..c1e2f2070
--- /dev/null
+++ b/contracts/extensions/test/utils/dutch_auction_test_wrapper.ts
@@ -0,0 +1,62 @@
+import { artifacts as protocolArtifacts } from '@0x/contracts-protocol';
+import { LogDecoder } from '@0x/contracts-test-utils';
+import { artifacts as tokensArtifacts } from '@0x/contracts-tokens';
+import { DutchAuctionDetails, SignedOrder } from '@0x/types';
+import { Web3Wrapper } from '@0x/web3-wrapper';
+import { Provider, TransactionReceiptWithDecodedLogs } from 'ethereum-types';
+import * as _ from 'lodash';
+
+import { DutchAuctionContract } from '../../generated-wrappers/dutch_auction';
+import { artifacts } from '../../src/artifacts';
+
+export class DutchAuctionTestWrapper {
+ private readonly _dutchAuctionContract: DutchAuctionContract;
+ private readonly _web3Wrapper: Web3Wrapper;
+ private readonly _logDecoder: LogDecoder;
+
+ constructor(contractInstance: DutchAuctionContract, provider: Provider) {
+ this._dutchAuctionContract = contractInstance;
+ this._web3Wrapper = new Web3Wrapper(provider);
+ this._logDecoder = new LogDecoder(this._web3Wrapper, {
+ ...artifacts,
+ ...tokensArtifacts,
+ ...protocolArtifacts,
+ });
+ }
+ /**
+ * Matches the buy and sell orders at an amount given the following: the current block time, the auction
+ * start time and the auction begin amount. The sell order is a an order at the lowest amount
+ * at the end of the auction. Excess from the match is transferred to the seller.
+ * Over time the price moves from beginAmount to endAmount given the current block.timestamp.
+ * @param buyOrder The Buyer's order. This order is for the current expected price of the auction.
+ * @param sellOrder The Seller's order. This order is for the lowest amount (at the end of the auction).
+ * @param from Address the transaction is being sent from.
+ * @return Transaction receipt with decoded logs.
+ */
+ public async matchOrdersAsync(
+ buyOrder: SignedOrder,
+ sellOrder: SignedOrder,
+ from: string,
+ ): Promise<TransactionReceiptWithDecodedLogs> {
+ const txHash = await this._dutchAuctionContract.matchOrders.sendTransactionAsync(
+ buyOrder,
+ sellOrder,
+ buyOrder.signature,
+ sellOrder.signature,
+ {
+ from,
+ },
+ );
+ const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
+ return tx;
+ }
+ /**
+ * Calculates the Auction Details for the given order
+ * @param sellOrder The Seller's order. This order is for the lowest amount (at the end of the auction).
+ * @return The dutch auction details.
+ */
+ public async getAuctionDetailsAsync(sellOrder: SignedOrder): Promise<DutchAuctionDetails> {
+ const auctionDetails = await this._dutchAuctionContract.getAuctionDetails.callAsync(sellOrder);
+ return auctionDetails;
+ }
+}
diff --git a/contracts/extensions/tsconfig.json b/contracts/extensions/tsconfig.json
index a303e3f5c..ed9b4fbe1 100644
--- a/contracts/extensions/tsconfig.json
+++ b/contracts/extensions/tsconfig.json
@@ -9,7 +9,9 @@
"files": [
"./generated-artifacts/BalanceThresholdFilter.json",
"./generated-artifacts/DutchAuction.json",
- "./generated-artifacts/Forwarder.json"
+ "./generated-artifacts/Forwarder.json",
+ "./generated-artifacts/OrderMatcher.json",
+ "./generated-artifacts/OrderValidator.json"
],
"exclude": ["./deploy/solc/solc_bin"]
}
diff --git a/contracts/interfaces/contracts/protocol/AssetProxy/IAssetData.sol b/contracts/interfaces/contracts/protocol/AssetProxy/IAssetData.sol
index e2da68919..a130e615f 100644
--- a/contracts/interfaces/contracts/protocol/AssetProxy/IAssetData.sol
+++ b/contracts/interfaces/contracts/protocol/AssetProxy/IAssetData.sol
@@ -17,7 +17,7 @@
*/
// solhint-disable
-pragma solidity 0.4.24;
+pragma solidity ^0.4.24;
pragma experimental ABIEncoderV2;
diff --git a/contracts/interfaces/contracts/protocol/AssetProxy/IAssetProxy.sol b/contracts/interfaces/contracts/protocol/AssetProxy/IAssetProxy.sol
index b25d2d75a..706412dd0 100644
--- a/contracts/interfaces/contracts/protocol/AssetProxy/IAssetProxy.sol
+++ b/contracts/interfaces/contracts/protocol/AssetProxy/IAssetProxy.sol
@@ -16,7 +16,7 @@
*/
-pragma solidity 0.4.24;
+pragma solidity ^0.4.24;
import "./IAuthorizable.sol";
diff --git a/contracts/interfaces/contracts/protocol/AssetProxy/IAuthorizable.sol b/contracts/interfaces/contracts/protocol/AssetProxy/IAuthorizable.sol
index 96ee05dee..202173998 100644
--- a/contracts/interfaces/contracts/protocol/AssetProxy/IAuthorizable.sol
+++ b/contracts/interfaces/contracts/protocol/AssetProxy/IAuthorizable.sol
@@ -16,7 +16,7 @@
*/
-pragma solidity 0.4.24;
+pragma solidity ^0.4.24;
import "@0x/contracts-utils/contracts/utils/Ownable/IOwnable.sol";
diff --git a/contracts/interfaces/contracts/protocol/Exchange/IAssetProxyDispatcher.sol b/contracts/interfaces/contracts/protocol/Exchange/IAssetProxyDispatcher.sol
index 8db8d6f6c..b73881c07 100644
--- a/contracts/interfaces/contracts/protocol/Exchange/IAssetProxyDispatcher.sol
+++ b/contracts/interfaces/contracts/protocol/Exchange/IAssetProxyDispatcher.sol
@@ -16,7 +16,7 @@
*/
-pragma solidity 0.4.24;
+pragma solidity ^0.4.24;
contract IAssetProxyDispatcher {
diff --git a/contracts/interfaces/contracts/protocol/Exchange/IExchange.sol b/contracts/interfaces/contracts/protocol/Exchange/IExchange.sol
index b92abba04..866e4c194 100644
--- a/contracts/interfaces/contracts/protocol/Exchange/IExchange.sol
+++ b/contracts/interfaces/contracts/protocol/Exchange/IExchange.sol
@@ -16,7 +16,7 @@
*/
-pragma solidity 0.4.24;
+pragma solidity ^0.4.24;
pragma experimental ABIEncoderV2;
import "./IExchangeCore.sol";
diff --git a/contracts/interfaces/contracts/protocol/Exchange/IExchangeCore.sol b/contracts/interfaces/contracts/protocol/Exchange/IExchangeCore.sol
index 0da73529c..ab4a62408 100644
--- a/contracts/interfaces/contracts/protocol/Exchange/IExchangeCore.sol
+++ b/contracts/interfaces/contracts/protocol/Exchange/IExchangeCore.sol
@@ -16,7 +16,7 @@
*/
-pragma solidity 0.4.24;
+pragma solidity ^0.4.24;
pragma experimental ABIEncoderV2;
import "@0x/contracts-libs/contracts/libs/LibOrder.sol";
diff --git a/contracts/interfaces/contracts/protocol/Exchange/IMatchOrders.sol b/contracts/interfaces/contracts/protocol/Exchange/IMatchOrders.sol
index b88e158c3..5df46ea80 100644
--- a/contracts/interfaces/contracts/protocol/Exchange/IMatchOrders.sol
+++ b/contracts/interfaces/contracts/protocol/Exchange/IMatchOrders.sol
@@ -15,7 +15,7 @@
limitations under the License.
*/
-pragma solidity 0.4.24;
+pragma solidity ^0.4.24;
pragma experimental ABIEncoderV2;
import "@0x/contracts-libs/contracts/libs/LibOrder.sol";
diff --git a/contracts/interfaces/contracts/protocol/Exchange/ISignatureValidator.sol b/contracts/interfaces/contracts/protocol/Exchange/ISignatureValidator.sol
index 1fd0eccf0..c5a4a57e1 100644
--- a/contracts/interfaces/contracts/protocol/Exchange/ISignatureValidator.sol
+++ b/contracts/interfaces/contracts/protocol/Exchange/ISignatureValidator.sol
@@ -16,7 +16,7 @@
*/
-pragma solidity 0.4.24;
+pragma solidity ^0.4.24;
contract ISignatureValidator {
diff --git a/contracts/interfaces/contracts/protocol/Exchange/ITransactions.sol b/contracts/interfaces/contracts/protocol/Exchange/ITransactions.sol
index 4446c55ce..aaaee389f 100644
--- a/contracts/interfaces/contracts/protocol/Exchange/ITransactions.sol
+++ b/contracts/interfaces/contracts/protocol/Exchange/ITransactions.sol
@@ -15,7 +15,7 @@
limitations under the License.
*/
-pragma solidity 0.4.24;
+pragma solidity ^0.4.24;
contract ITransactions {
diff --git a/contracts/interfaces/contracts/protocol/Exchange/IValidator.sol b/contracts/interfaces/contracts/protocol/Exchange/IValidator.sol
index 2dd69100c..d214e54dd 100644
--- a/contracts/interfaces/contracts/protocol/Exchange/IValidator.sol
+++ b/contracts/interfaces/contracts/protocol/Exchange/IValidator.sol
@@ -16,7 +16,7 @@
*/
-pragma solidity 0.4.24;
+pragma solidity ^0.4.24;
contract IValidator {
diff --git a/contracts/interfaces/contracts/protocol/Exchange/IWallet.sol b/contracts/interfaces/contracts/protocol/Exchange/IWallet.sol
index c97161ca6..c2db4a5b1 100644
--- a/contracts/interfaces/contracts/protocol/Exchange/IWallet.sol
+++ b/contracts/interfaces/contracts/protocol/Exchange/IWallet.sol
@@ -16,7 +16,7 @@
*/
-pragma solidity 0.4.24;
+pragma solidity ^0.4.24;
contract IWallet {
diff --git a/contracts/interfaces/contracts/protocol/Exchange/IWrapperFunctions.sol b/contracts/interfaces/contracts/protocol/Exchange/IWrapperFunctions.sol
index 833bb7e88..0eeaa874b 100644
--- a/contracts/interfaces/contracts/protocol/Exchange/IWrapperFunctions.sol
+++ b/contracts/interfaces/contracts/protocol/Exchange/IWrapperFunctions.sol
@@ -16,7 +16,7 @@
*/
-pragma solidity 0.4.24;
+pragma solidity ^0.4.24;
pragma experimental ABIEncoderV2;
import "@0x/contracts-libs/contracts/libs/LibOrder.sol";
diff --git a/contracts/interfaces/package.json b/contracts/interfaces/package.json
index 4d3e4b7f9..15385a154 100644
--- a/contracts/interfaces/package.json
+++ b/contracts/interfaces/package.json
@@ -10,7 +10,8 @@
"build": "yarn pre_build && tsc -b",
"build:ci": "yarn build",
"pre_build": "run-s compile generate_contract_wrappers",
- "compile": "sol-compiler --contracts-dir contracts",
+ "compile": "sol-compiler",
+ "watch": "sol-compiler -w",
"clean": "shx rm -rf lib generated-artifacts generated-wrappers",
"generate_contract_wrappers": "abi-gen --abis ${npm_package_config_abis} --template ../../node_modules/@0x/abi-gen-templates/contract.handlebars --partials '../../node_modules/@0x/abi-gen-templates/partials/**/*.handlebars' --output generated-wrappers --backend ethers",
"lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
diff --git a/contracts/libs/compiler.json b/contracts/libs/compiler.json
index cf7c52a73..349d3063b 100644
--- a/contracts/libs/compiler.json
+++ b/contracts/libs/compiler.json
@@ -18,5 +18,14 @@
}
}
},
- "contracts": ["TestLibs", "LibOrder", "LibMath", "LibFillResults", "LibAbiEncoder", "LibEIP712"]
+ "contracts": [
+ "TestLibs",
+ "LibOrder",
+ "LibMath",
+ "LibFillResults",
+ "LibAbiEncoder",
+ "LibEIP712",
+ "LibAssetProxyErrors",
+ "LibConstants"
+ ]
}
diff --git a/contracts/libs/contracts/libs/LibAbiEncoder.sol b/contracts/libs/contracts/libs/LibAbiEncoder.sol
index 4aad37709..5422bfeec 100644
--- a/contracts/libs/contracts/libs/LibAbiEncoder.sol
+++ b/contracts/libs/contracts/libs/LibAbiEncoder.sol
@@ -16,7 +16,7 @@
*/
-pragma solidity 0.4.24;
+pragma solidity ^0.4.24;
pragma experimental ABIEncoderV2;
import "./LibOrder.sol";
diff --git a/contracts/libs/contracts/libs/LibAddressArray.sol b/contracts/libs/contracts/libs/LibAddressArray.sol
index ccae2ac5f..997ce85fa 100644
--- a/contracts/libs/contracts/libs/LibAddressArray.sol
+++ b/contracts/libs/contracts/libs/LibAddressArray.sol
@@ -16,7 +16,7 @@
*/
-pragma solidity 0.4.24;
+pragma solidity ^0.4.24;
import "@0x/contracts-utils/contracts/utils/LibBytes/LibBytes.sol";
diff --git a/contracts/libs/contracts/libs/LibAssetProxyErrors.sol b/contracts/libs/contracts/libs/LibAssetProxyErrors.sol
index 1d9a70cc1..96c48b5e3 100644
--- a/contracts/libs/contracts/libs/LibAssetProxyErrors.sol
+++ b/contracts/libs/contracts/libs/LibAssetProxyErrors.sol
@@ -17,7 +17,7 @@
*/
// solhint-disable
-pragma solidity 0.4.24;
+pragma solidity ^0.4.24;
/// @dev This contract documents the revert reasons used in the AssetProxy contracts.
diff --git a/contracts/libs/contracts/libs/LibConstants.sol b/contracts/libs/contracts/libs/LibConstants.sol
index 8d2732cd3..3efa3e1b3 100644
--- a/contracts/libs/contracts/libs/LibConstants.sol
+++ b/contracts/libs/contracts/libs/LibConstants.sol
@@ -16,7 +16,7 @@
*/
-pragma solidity 0.4.24;
+pragma solidity ^0.4.24;
// solhint-disable max-line-length
diff --git a/contracts/libs/contracts/libs/LibEIP712.sol b/contracts/libs/contracts/libs/LibEIP712.sol
index 203edc1fd..3a85ab3c0 100644
--- a/contracts/libs/contracts/libs/LibEIP712.sol
+++ b/contracts/libs/contracts/libs/LibEIP712.sol
@@ -16,7 +16,7 @@
*/
-pragma solidity 0.4.24;
+pragma solidity ^0.4.24;
contract LibEIP712 {
diff --git a/contracts/libs/contracts/libs/LibExchangeErrors.sol b/contracts/libs/contracts/libs/LibExchangeErrors.sol
index a0f75bc06..a160242c9 100644
--- a/contracts/libs/contracts/libs/LibExchangeErrors.sol
+++ b/contracts/libs/contracts/libs/LibExchangeErrors.sol
@@ -17,7 +17,7 @@
*/
// solhint-disable
-pragma solidity 0.4.24;
+pragma solidity ^0.4.24;
/// @dev This contract documents the revert reasons used in the Exchange contract.
diff --git a/contracts/libs/contracts/libs/LibExchangeSelectors.sol b/contracts/libs/contracts/libs/LibExchangeSelectors.sol
index edb4f9cbd..71640c609 100644
--- a/contracts/libs/contracts/libs/LibExchangeSelectors.sol
+++ b/contracts/libs/contracts/libs/LibExchangeSelectors.sol
@@ -16,7 +16,7 @@
*/
-pragma solidity 0.4.24;
+pragma solidity ^0.4.24;
contract LibExchangeSelectors {
diff --git a/contracts/libs/contracts/libs/LibFillResults.sol b/contracts/libs/contracts/libs/LibFillResults.sol
index fbd9950bf..74b7f7984 100644
--- a/contracts/libs/contracts/libs/LibFillResults.sol
+++ b/contracts/libs/contracts/libs/LibFillResults.sol
@@ -16,7 +16,7 @@
*/
-pragma solidity 0.4.24;
+pragma solidity ^0.4.24;
import "@0x/contracts-utils/contracts/utils/SafeMath/SafeMath.sol";
diff --git a/contracts/libs/contracts/libs/LibMath.sol b/contracts/libs/contracts/libs/LibMath.sol
index b24876a9c..f14b1b34d 100644
--- a/contracts/libs/contracts/libs/LibMath.sol
+++ b/contracts/libs/contracts/libs/LibMath.sol
@@ -16,7 +16,7 @@
*/
-pragma solidity 0.4.24;
+pragma solidity ^0.4.24;
import "@0x/contracts-utils/contracts/utils/SafeMath/SafeMath.sol";
diff --git a/contracts/libs/contracts/libs/LibOrder.sol b/contracts/libs/contracts/libs/LibOrder.sol
index 0fe7c2161..fcf5da5fb 100644
--- a/contracts/libs/contracts/libs/LibOrder.sol
+++ b/contracts/libs/contracts/libs/LibOrder.sol
@@ -16,7 +16,7 @@
*/
-pragma solidity 0.4.24;
+pragma solidity ^0.4.24;
import "./LibEIP712.sol";
diff --git a/contracts/libs/package.json b/contracts/libs/package.json
index fa4b6e523..ce7b97502 100644
--- a/contracts/libs/package.json
+++ b/contracts/libs/package.json
@@ -19,7 +19,8 @@
"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 --require make-promises-safe 'lib/test/**/*.js' --timeout 100000 --bail --exit",
- "compile": "sol-compiler --contracts-dir contracts",
+ "compile": "sol-compiler",
+ "watch": "sol-compiler -w",
"clean": "shx rm -rf lib generated-artifacts generated-wrappers",
"generate_contract_wrappers": "abi-gen --abis ${npm_package_config_abis} --template ../../node_modules/@0x/abi-gen-templates/contract.handlebars --partials '../../node_modules/@0x/abi-gen-templates/partials/**/*.handlebars' --output generated-wrappers --backend ethers",
"lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
diff --git a/contracts/multisig/package.json b/contracts/multisig/package.json
index b338f67f7..2d7b4aa05 100644
--- a/contracts/multisig/package.json
+++ b/contracts/multisig/package.json
@@ -19,7 +19,8 @@
"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 --require make-promises-safe 'lib/test/**/*.js' --timeout 100000 --bail --exit",
- "compile": "sol-compiler --contracts-dir contracts",
+ "compile": "sol-compiler",
+ "watch": "sol-compiler -w",
"clean": "shx rm -rf lib generated-artifacts generated-wrappers",
"generate_contract_wrappers": "abi-gen --abis ${npm_package_config_abis} --template ../../packages/abi-gen-templates/contract.handlebars --partials '../../packages/abi-gen-templates/partials/**/*.handlebars' --output generated-wrappers --backend ethers",
"lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
diff --git a/contracts/protocol/CHANGELOG.json b/contracts/protocol/CHANGELOG.json
index 2dca9794a..e283d7917 100644
--- a/contracts/protocol/CHANGELOG.json
+++ b/contracts/protocol/CHANGELOG.json
@@ -5,6 +5,14 @@
{
"note": "Added LibAddressArray",
"pr": 1383
+ },
+ {
+ "note": "Add validation and comments to MultiAssetProxy",
+ "pr": 1455
+ },
+ {
+ "note": "Move OrderValidator to extensions",
+ "pr": 1464
}
]
},
diff --git a/contracts/protocol/compiler.json b/contracts/protocol/compiler.json
index c05d62aba..10e5bb0a1 100644
--- a/contracts/protocol/compiler.json
+++ b/contracts/protocol/compiler.json
@@ -25,7 +25,6 @@
"Exchange",
"MixinAuthorizable",
"MultiAssetProxy",
- "OrderValidator",
"TestAssetProxyOwner",
"TestAssetProxyDispatcher",
"TestExchangeInternals",
diff --git a/contracts/protocol/contracts/protocol/AssetProxy/MixinAuthorizable.sol b/contracts/protocol/contracts/protocol/AssetProxy/MixinAuthorizable.sol
index 08f9b94dc..b610ef709 100644
--- a/contracts/protocol/contracts/protocol/AssetProxy/MixinAuthorizable.sol
+++ b/contracts/protocol/contracts/protocol/AssetProxy/MixinAuthorizable.sol
@@ -16,7 +16,7 @@
*/
-pragma solidity 0.4.24;
+pragma solidity ^0.4.24;
import "@0x/contracts-utils/contracts/utils/Ownable/Ownable.sol";
import "./mixins/MAuthorizable.sol";
diff --git a/contracts/protocol/contracts/protocol/AssetProxy/MultiAssetProxy.sol b/contracts/protocol/contracts/protocol/AssetProxy/MultiAssetProxy.sol
index 42231e73b..5f559163c 100644
--- a/contracts/protocol/contracts/protocol/AssetProxy/MultiAssetProxy.sol
+++ b/contracts/protocol/contracts/protocol/AssetProxy/MultiAssetProxy.sol
@@ -33,6 +33,9 @@ contract MultiAssetProxy is
function ()
external
{
+ // NOTE: The below assembly assumes that clients do some input validation and that the input is properly encoded according to the AbiV2 specification.
+ // It is technically possible for inputs with very large lengths and offsets to cause overflows. However, this would make the calldata prohibitively
+ // expensive and we therefore do not check for overflows in these scenarios.
assembly {
// The first 4 bytes of calldata holds the function selector
let selector := and(calldataload(0), 0xffffffff00000000000000000000000000000000000000000000000000000000)
@@ -145,7 +148,7 @@ contract MultiAssetProxy is
let nestedAssetDataLen := calldataload(sub(nestedAssetDataContentsStart, 32))
// Revert if number of elements in `amounts` differs from number of elements in `nestedAssetData`
- if iszero(eq(amountsLen, nestedAssetDataLen)) {
+ if sub(amountsLen, nestedAssetDataLen) {
// Revert with `Error("LENGTH_MISMATCH")`
mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
@@ -181,8 +184,11 @@ contract MultiAssetProxy is
let amountsElement := calldataload(add(amountsContentsStart, i))
let totalAmount := mul(amountsElement, amount)
- // Revert if multiplication resulted in an overflow
- if iszero(eq(div(totalAmount, amount), amountsElement)) {
+ // Revert if `amount` != 0 and multiplication resulted in an overflow
+ if iszero(or(
+ iszero(amount),
+ eq(div(totalAmount, amount), amountsElement)
+ )) {
// Revert with `Error("UINT256_OVERFLOW")`
mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
@@ -230,7 +236,7 @@ contract MultiAssetProxy is
// Only load `assetProxy` if `currentAssetProxyId` does not equal `assetProxyId`
// We do not need to check if `currentAssetProxyId` is 0 since `assetProxy` is also initialized to 0
- if iszero(eq(currentAssetProxyId, assetProxyId)) {
+ if sub(currentAssetProxyId, assetProxyId) {
// Update `assetProxyId`
assetProxyId := currentAssetProxyId
// To lookup a value in a mapping, we load from the storage location keccak256(k, p),
diff --git a/contracts/protocol/contracts/protocol/AssetProxy/mixins/MAuthorizable.sol b/contracts/protocol/contracts/protocol/AssetProxy/mixins/MAuthorizable.sol
index fe77048ce..6c3f70500 100644
--- a/contracts/protocol/contracts/protocol/AssetProxy/mixins/MAuthorizable.sol
+++ b/contracts/protocol/contracts/protocol/AssetProxy/mixins/MAuthorizable.sol
@@ -16,7 +16,7 @@
*/
-pragma solidity 0.4.24;
+pragma solidity ^0.4.24;
import "@0x/contracts-interfaces/contracts/protocol/AssetProxy/IAuthorizable.sol";
diff --git a/contracts/protocol/contracts/protocol/Exchange/MixinAssetProxyDispatcher.sol b/contracts/protocol/contracts/protocol/Exchange/MixinAssetProxyDispatcher.sol
index 36ab39b45..2922a8c1a 100644
--- a/contracts/protocol/contracts/protocol/Exchange/MixinAssetProxyDispatcher.sol
+++ b/contracts/protocol/contracts/protocol/Exchange/MixinAssetProxyDispatcher.sol
@@ -16,7 +16,7 @@
*/
-pragma solidity 0.4.24;
+pragma solidity ^0.4.24;
import "@0x/contracts-utils/contracts/utils/Ownable/Ownable.sol";
import "./mixins/MAssetProxyDispatcher.sol";
diff --git a/contracts/protocol/contracts/protocol/Exchange/MixinExchangeCore.sol b/contracts/protocol/contracts/protocol/Exchange/MixinExchangeCore.sol
index 68d6a3897..72bcebc62 100644
--- a/contracts/protocol/contracts/protocol/Exchange/MixinExchangeCore.sol
+++ b/contracts/protocol/contracts/protocol/Exchange/MixinExchangeCore.sol
@@ -16,7 +16,7 @@
*/
-pragma solidity 0.4.24;
+pragma solidity ^0.4.24;
pragma experimental ABIEncoderV2;
import "@0x/contracts-utils/contracts/utils/ReentrancyGuard/ReentrancyGuard.sol";
diff --git a/contracts/protocol/contracts/protocol/Exchange/MixinMatchOrders.sol b/contracts/protocol/contracts/protocol/Exchange/MixinMatchOrders.sol
index fc6d73482..2627b82fd 100644
--- a/contracts/protocol/contracts/protocol/Exchange/MixinMatchOrders.sol
+++ b/contracts/protocol/contracts/protocol/Exchange/MixinMatchOrders.sol
@@ -11,7 +11,7 @@
limitations under the License.
*/
-pragma solidity 0.4.24;
+pragma solidity ^0.4.24;
pragma experimental ABIEncoderV2;
import "@0x/contracts-utils/contracts/utils/ReentrancyGuard/ReentrancyGuard.sol";
diff --git a/contracts/protocol/contracts/protocol/Exchange/MixinSignatureValidator.sol b/contracts/protocol/contracts/protocol/Exchange/MixinSignatureValidator.sol
index 80b4c0755..b40aa1412 100644
--- a/contracts/protocol/contracts/protocol/Exchange/MixinSignatureValidator.sol
+++ b/contracts/protocol/contracts/protocol/Exchange/MixinSignatureValidator.sol
@@ -16,7 +16,7 @@
*/
-pragma solidity 0.4.24;
+pragma solidity ^0.4.24;
import "@0x/contracts-utils/contracts/utils/LibBytes/LibBytes.sol";
import "@0x/contracts-utils/contracts/utils/ReentrancyGuard/ReentrancyGuard.sol";
diff --git a/contracts/protocol/contracts/protocol/Exchange/MixinTransactions.sol b/contracts/protocol/contracts/protocol/Exchange/MixinTransactions.sol
index 87c614382..1ac5b1a5e 100644
--- a/contracts/protocol/contracts/protocol/Exchange/MixinTransactions.sol
+++ b/contracts/protocol/contracts/protocol/Exchange/MixinTransactions.sol
@@ -15,7 +15,7 @@
limitations under the License.
*/
-pragma solidity 0.4.24;
+pragma solidity ^0.4.24;
import "@0x/contracts-libs/contracts/libs/LibExchangeErrors.sol";
import "./mixins/MSignatureValidator.sol";
diff --git a/contracts/protocol/contracts/protocol/Exchange/MixinWrapperFunctions.sol b/contracts/protocol/contracts/protocol/Exchange/MixinWrapperFunctions.sol
index 2d43432ff..6fc6ee999 100644
--- a/contracts/protocol/contracts/protocol/Exchange/MixinWrapperFunctions.sol
+++ b/contracts/protocol/contracts/protocol/Exchange/MixinWrapperFunctions.sol
@@ -16,7 +16,7 @@
*/
-pragma solidity 0.4.24;
+pragma solidity ^0.4.24;
pragma experimental ABIEncoderV2;
import "@0x/contracts-utils/contracts/utils/ReentrancyGuard/ReentrancyGuard.sol";
diff --git a/contracts/protocol/contracts/protocol/Exchange/mixins/MAssetProxyDispatcher.sol b/contracts/protocol/contracts/protocol/Exchange/mixins/MAssetProxyDispatcher.sol
index fe3d03326..05c2c4c0b 100644
--- a/contracts/protocol/contracts/protocol/Exchange/mixins/MAssetProxyDispatcher.sol
+++ b/contracts/protocol/contracts/protocol/Exchange/mixins/MAssetProxyDispatcher.sol
@@ -16,7 +16,7 @@
*/
-pragma solidity 0.4.24;
+pragma solidity ^0.4.24;
import "@0x/contracts-interfaces/contracts/protocol/Exchange/IAssetProxyDispatcher.sol";
diff --git a/contracts/protocol/contracts/protocol/Exchange/mixins/MExchangeCore.sol b/contracts/protocol/contracts/protocol/Exchange/mixins/MExchangeCore.sol
index 215284900..09dc491cd 100644
--- a/contracts/protocol/contracts/protocol/Exchange/mixins/MExchangeCore.sol
+++ b/contracts/protocol/contracts/protocol/Exchange/mixins/MExchangeCore.sol
@@ -16,7 +16,7 @@
*/
-pragma solidity 0.4.24;
+pragma solidity ^0.4.24;
pragma experimental ABIEncoderV2;
import "@0x/contracts-libs/contracts/libs/LibOrder.sol";
diff --git a/contracts/protocol/contracts/protocol/Exchange/mixins/MMatchOrders.sol b/contracts/protocol/contracts/protocol/Exchange/mixins/MMatchOrders.sol
index 1eb4be329..56ee895c4 100644
--- a/contracts/protocol/contracts/protocol/Exchange/mixins/MMatchOrders.sol
+++ b/contracts/protocol/contracts/protocol/Exchange/mixins/MMatchOrders.sol
@@ -15,7 +15,7 @@
limitations under the License.
*/
-pragma solidity 0.4.24;
+pragma solidity ^0.4.24;
pragma experimental ABIEncoderV2;
import "@0x/contracts-libs/contracts/libs/LibOrder.sol";
diff --git a/contracts/protocol/contracts/protocol/Exchange/mixins/MSignatureValidator.sol b/contracts/protocol/contracts/protocol/Exchange/mixins/MSignatureValidator.sol
index a933976d1..6407760d4 100644
--- a/contracts/protocol/contracts/protocol/Exchange/mixins/MSignatureValidator.sol
+++ b/contracts/protocol/contracts/protocol/Exchange/mixins/MSignatureValidator.sol
@@ -16,7 +16,7 @@
*/
-pragma solidity 0.4.24;
+pragma solidity ^0.4.24;
import "@0x/contracts-interfaces/contracts/protocol/Exchange/ISignatureValidator.sol";
diff --git a/contracts/protocol/contracts/protocol/Exchange/mixins/MTransactions.sol b/contracts/protocol/contracts/protocol/Exchange/mixins/MTransactions.sol
index a6b0fdc85..04dd716d7 100644
--- a/contracts/protocol/contracts/protocol/Exchange/mixins/MTransactions.sol
+++ b/contracts/protocol/contracts/protocol/Exchange/mixins/MTransactions.sol
@@ -15,7 +15,7 @@
limitations under the License.
*/
-pragma solidity 0.4.24;
+pragma solidity ^0.4.24;
import "@0x/contracts-interfaces/contracts/protocol/Exchange/ITransactions.sol";
diff --git a/contracts/protocol/contracts/protocol/Exchange/mixins/MWrapperFunctions.sol b/contracts/protocol/contracts/protocol/Exchange/mixins/MWrapperFunctions.sol
index 101e7cb82..2ff3b8790 100644
--- a/contracts/protocol/contracts/protocol/Exchange/mixins/MWrapperFunctions.sol
+++ b/contracts/protocol/contracts/protocol/Exchange/mixins/MWrapperFunctions.sol
@@ -16,7 +16,7 @@
*/
-pragma solidity 0.4.24;
+pragma solidity ^0.4.24;
pragma experimental ABIEncoderV2;
import "@0x/contracts-libs/contracts/libs/LibOrder.sol";
diff --git a/contracts/protocol/package.json b/contracts/protocol/package.json
index 122ce07c3..891838e54 100644
--- a/contracts/protocol/package.json
+++ b/contracts/protocol/package.json
@@ -19,7 +19,8 @@
"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 --require make-promises-safe 'lib/test/**/*.js' --timeout 100000 --bail --exit",
- "compile": "sol-compiler --contracts-dir contracts",
+ "compile": "sol-compiler",
+ "watch": "sol-compiler -w",
"clean": "shx rm -rf lib generated-artifacts generated-wrappers",
"generate_contract_wrappers": "abi-gen --abis ${npm_package_config_abis} --template ../../node_modules/@0x/abi-gen-templates/contract.handlebars --partials '../../node_modules/@0x/abi-gen-templates/partials/**/*.handlebars' --output generated-wrappers --backend ethers",
"lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
@@ -31,7 +32,7 @@
"lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol"
},
"config": {
- "abis": "generated-artifacts/@(AssetProxyOwner|ERC20Proxy|ERC721Proxy|Exchange|MixinAuthorizable|MultiAssetProxy|OrderValidator|TestSignatureValidator|TestAssetProxyOwner|TestAssetProxyDispatcher|TestExchangeInternals|TestStaticCallReceiver).json"
+ "abis": "generated-artifacts/@(AssetProxyOwner|ERC20Proxy|ERC721Proxy|Exchange|MixinAuthorizable|MultiAssetProxy|TestSignatureValidator|TestAssetProxyOwner|TestAssetProxyDispatcher|TestExchangeInternals|TestStaticCallReceiver).json"
},
"repository": {
"type": "git",
diff --git a/contracts/protocol/src/artifacts/index.ts b/contracts/protocol/src/artifacts/index.ts
index 1d53ceb04..c5d12f10b 100644
--- a/contracts/protocol/src/artifacts/index.ts
+++ b/contracts/protocol/src/artifacts/index.ts
@@ -6,7 +6,6 @@ import * as ERC721Proxy from '../../generated-artifacts/ERC721Proxy.json';
import * as Exchange from '../../generated-artifacts/Exchange.json';
import * as MixinAuthorizable from '../../generated-artifacts/MixinAuthorizable.json';
import * as MultiAssetProxy from '../../generated-artifacts/MultiAssetProxy.json';
-import * as OrderValidator from '../../generated-artifacts/OrderValidator.json';
import * as TestAssetProxyDispatcher from '../../generated-artifacts/TestAssetProxyDispatcher.json';
import * as TestAssetProxyOwner from '../../generated-artifacts/TestAssetProxyOwner.json';
import * as TestExchangeInternals from '../../generated-artifacts/TestExchangeInternals.json';
@@ -20,7 +19,6 @@ export const artifacts = {
Exchange: Exchange as ContractArtifact,
MixinAuthorizable: MixinAuthorizable as ContractArtifact,
MultiAssetProxy: MultiAssetProxy as ContractArtifact,
- OrderValidator: OrderValidator as ContractArtifact,
TestAssetProxyDispatcher: TestAssetProxyDispatcher as ContractArtifact,
TestAssetProxyOwner: TestAssetProxyOwner as ContractArtifact,
TestExchangeInternals: TestExchangeInternals as ContractArtifact,
diff --git a/contracts/protocol/src/wrappers/index.ts b/contracts/protocol/src/wrappers/index.ts
index ac951d269..01b121054 100644
--- a/contracts/protocol/src/wrappers/index.ts
+++ b/contracts/protocol/src/wrappers/index.ts
@@ -3,7 +3,6 @@ export * from '../../generated-wrappers/erc20_proxy';
export * from '../../generated-wrappers/erc721_proxy';
export * from '../../generated-wrappers/exchange';
export * from '../../generated-wrappers/mixin_authorizable';
-export * from '../../generated-wrappers/order_validator';
export * from '../../generated-wrappers/test_asset_proxy_dispatcher';
export * from '../../generated-wrappers/test_asset_proxy_owner';
export * from '../../generated-wrappers/test_exchange_internals';
diff --git a/contracts/protocol/test/asset_proxy/proxies.ts b/contracts/protocol/test/asset_proxy/proxies.ts
index c4bd95905..bbb44f402 100644
--- a/contracts/protocol/test/asset_proxy/proxies.ts
+++ b/contracts/protocol/test/asset_proxy/proxies.ts
@@ -12,6 +12,7 @@ import {
import {
artifacts as tokensArtifacts,
DummyERC20TokenContract,
+ DummyERC20TokenTransferEventArgs,
DummyERC721ReceiverContract,
DummyERC721TokenContract,
DummyMultipleReturnERC20TokenContract,
@@ -22,6 +23,7 @@ import { assetDataUtils } from '@0x/order-utils';
import { RevertReason } from '@0x/types';
import { BigNumber } from '@0x/utils';
import * as chai from 'chai';
+import { LogWithDecodedArgs } from 'ethereum-types';
import * as _ from 'lodash';
import { ERC20ProxyContract } from '../../generated-wrappers/erc20_proxy';
@@ -713,7 +715,7 @@ describe('Asset Transfer Proxies', () => {
const erc20AssetData = assetDataUtils.encodeERC20AssetData(erc20TokenA.address);
const amounts = [erc20Amount];
const nestedAssetData = [erc20AssetData];
- const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
+ const assetData = assetDataUtils.encodeMultiAssetData(amounts, nestedAssetData);
const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
assetData,
fromAddress,
@@ -738,6 +740,36 @@ describe('Asset Transfer Proxies', () => {
erc20Balances[toAddress][erc20TokenA.address].add(totalAmount),
);
});
+ it('should dispatch an ERC20 transfer when input amount is 0', async () => {
+ const inputAmount = constants.ZERO_AMOUNT;
+ const erc20Amount = new BigNumber(10);
+ const erc20AssetData = assetDataUtils.encodeERC20AssetData(erc20TokenA.address);
+ const amounts = [erc20Amount];
+ const nestedAssetData = [erc20AssetData];
+ const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
+ const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
+ assetData,
+ fromAddress,
+ toAddress,
+ inputAmount,
+ );
+ const erc20Balances = await erc20Wrapper.getBalancesAsync();
+ const logDecoder = new LogDecoder(web3Wrapper, { ...artifacts, ...tokensArtifacts });
+ const tx = await logDecoder.getTxWithDecodedLogsAsync(
+ await web3Wrapper.sendTransactionAsync({
+ to: multiAssetProxy.address,
+ data,
+ from: authorized,
+ }),
+ );
+ expect(tx.logs.length).to.be.equal(1);
+ const log = tx.logs[0] as LogWithDecodedArgs<DummyERC20TokenTransferEventArgs>;
+ const transferEventName = 'Transfer';
+ expect(log.event).to.equal(transferEventName);
+ expect(log.args._value).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ const newBalances = await erc20Wrapper.getBalancesAsync();
+ expect(newBalances).to.deep.equal(erc20Balances);
+ });
it('should successfully transfer multiple of the same ERC20 token', async () => {
const inputAmount = new BigNumber(1);
const erc20Amount1 = new BigNumber(10);
@@ -746,7 +778,7 @@ describe('Asset Transfer Proxies', () => {
const erc20AssetData2 = assetDataUtils.encodeERC20AssetData(erc20TokenA.address);
const amounts = [erc20Amount1, erc20Amount2];
const nestedAssetData = [erc20AssetData1, erc20AssetData2];
- const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
+ const assetData = assetDataUtils.encodeMultiAssetData(amounts, nestedAssetData);
const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
assetData,
fromAddress,
@@ -779,7 +811,7 @@ describe('Asset Transfer Proxies', () => {
const erc20AssetData2 = assetDataUtils.encodeERC20AssetData(erc20TokenB.address);
const amounts = [erc20Amount1, erc20Amount2];
const nestedAssetData = [erc20AssetData1, erc20AssetData2];
- const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
+ const assetData = assetDataUtils.encodeMultiAssetData(amounts, nestedAssetData);
const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
assetData,
fromAddress,
@@ -817,7 +849,7 @@ describe('Asset Transfer Proxies', () => {
const erc721AssetData = assetDataUtils.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
const amounts = [erc721Amount];
const nestedAssetData = [erc721AssetData];
- const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
+ const assetData = assetDataUtils.encodeMultiAssetData(amounts, nestedAssetData);
const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
assetData,
fromAddress,
@@ -849,7 +881,7 @@ describe('Asset Transfer Proxies', () => {
const erc721Amount = new BigNumber(1);
const amounts = [erc721Amount, erc721Amount];
const nestedAssetData = [erc721AssetData1, erc721AssetData2];
- const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
+ const assetData = assetDataUtils.encodeMultiAssetData(amounts, nestedAssetData);
const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
assetData,
fromAddress,
@@ -881,7 +913,7 @@ describe('Asset Transfer Proxies', () => {
const erc721Amount = new BigNumber(1);
const amounts = [erc721Amount, erc721Amount];
const nestedAssetData = [erc721AssetData1, erc721AssetData2];
- const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
+ const assetData = assetDataUtils.encodeMultiAssetData(amounts, nestedAssetData);
const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
assetData,
fromAddress,
@@ -914,7 +946,7 @@ describe('Asset Transfer Proxies', () => {
const erc721AssetData = assetDataUtils.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
const amounts = [erc20Amount, erc721Amount];
const nestedAssetData = [erc20AssetData, erc721AssetData];
- const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
+ const assetData = assetDataUtils.encodeMultiAssetData(amounts, nestedAssetData);
const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
assetData,
fromAddress,
@@ -952,10 +984,7 @@ describe('Asset Transfer Proxies', () => {
const amounts = [erc20Amount, erc721Amount];
const nestedAssetData = [erc20AssetData, erc721AssetData];
const extraData = '0102030405060708';
- const assetData = `${assetDataInterface.MultiAsset.getABIEncodedTransactionData(
- amounts,
- nestedAssetData,
- )}${extraData}`;
+ const assetData = `${assetDataUtils.encodeMultiAssetData(amounts, nestedAssetData)}${extraData}`;
const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
assetData,
fromAddress,
@@ -992,7 +1021,7 @@ describe('Asset Transfer Proxies', () => {
const erc20AssetData2 = assetDataUtils.encodeERC20AssetData(erc20TokenB.address);
const amounts = [erc20Amount1, erc20Amount2];
const nestedAssetData = [erc20AssetData1, erc20AssetData2];
- const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
+ const assetData = assetDataUtils.encodeMultiAssetData(amounts, nestedAssetData);
const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
assetData,
fromAddress,
@@ -1053,7 +1082,7 @@ describe('Asset Transfer Proxies', () => {
erc721AssetData3,
erc721AssetData4,
];
- const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
+ const assetData = assetDataUtils.encodeMultiAssetData(amounts, nestedAssetData);
const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
assetData,
fromAddress,
@@ -1111,7 +1140,7 @@ describe('Asset Transfer Proxies', () => {
const erc721AssetData = assetDataUtils.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
const amounts = [erc20Amount, erc721Amount];
const nestedAssetData = [erc20AssetData, erc721AssetData];
- const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
+ const assetData = assetDataUtils.encodeMultiAssetData(amounts, nestedAssetData);
const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
assetData,
fromAddress,
@@ -1137,6 +1166,7 @@ describe('Asset Transfer Proxies', () => {
const invalidErc721AssetData = `${invalidProxyId}${erc721AssetData.slice(10)}`;
const amounts = [erc20Amount, erc721Amount];
const nestedAssetData = [erc20AssetData, invalidErc721AssetData];
+ // HACK: This is used to get around validation built into assetDataUtils
const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
assetData,
@@ -1160,6 +1190,7 @@ describe('Asset Transfer Proxies', () => {
const erc721AssetData = assetDataUtils.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
const amounts = [erc20Amount];
const nestedAssetData = [erc20AssetData, erc721AssetData];
+ // HACK: This is used to get around validation built into assetDataUtils
const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
assetData,
@@ -1182,7 +1213,7 @@ describe('Asset Transfer Proxies', () => {
const erc20AssetData = assetDataUtils.encodeERC20AssetData(erc20TokenA.address);
const amounts = [erc20Amount];
const nestedAssetData = [erc20AssetData];
- const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
+ const assetData = assetDataUtils.encodeMultiAssetData(amounts, nestedAssetData);
const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
assetData,
fromAddress,
@@ -1206,6 +1237,7 @@ describe('Asset Transfer Proxies', () => {
const erc721AssetData = '0x123456';
const amounts = [erc20Amount, erc721Amount];
const nestedAssetData = [erc20AssetData, erc721AssetData];
+ // HACK: This is used to get around validation built into assetDataUtils
const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
assetData,
@@ -1230,7 +1262,7 @@ describe('Asset Transfer Proxies', () => {
const erc721AssetData = assetDataUtils.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
const amounts = [erc20Amount, erc721Amount];
const nestedAssetData = [erc20AssetData, erc721AssetData];
- const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
+ const assetData = assetDataUtils.encodeMultiAssetData(amounts, nestedAssetData);
const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
assetData,
fromAddress,
diff --git a/contracts/protocol/test/exchange/core.ts b/contracts/protocol/test/exchange/core.ts
index 9b948f991..42db8623d 100644
--- a/contracts/protocol/test/exchange/core.ts
+++ b/contracts/protocol/test/exchange/core.ts
@@ -1,4 +1,3 @@
-import { artifacts as interfacesArtifacts, IAssetDataContract } from '@0x/contracts-interfaces';
import {
chaiSetup,
constants,
@@ -43,11 +42,6 @@ import { ExchangeWrapper } from '../utils/exchange_wrapper';
chaiSetup.configure();
const expect = chai.expect;
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
-const assetDataInterface = new IAssetDataContract(
- interfacesArtifacts.IAssetData.compilerOutput.abi,
- constants.NULL_ADDRESS,
- provider,
-);
// tslint:disable:no-unnecessary-type-assertion
describe('Exchange core', () => {
let makerAddress: string;
@@ -777,10 +771,7 @@ describe('Exchange core', () => {
assetDataUtils.encodeERC20AssetData(erc20TokenA.address),
assetDataUtils.encodeERC20AssetData(erc20TokenB.address),
];
- const makerAssetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(
- makerAmounts,
- makerNestedAssetData,
- );
+ const makerAssetData = assetDataUtils.encodeMultiAssetData(makerAmounts, makerNestedAssetData);
const makerAssetAmount = new BigNumber(1);
const takerAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address);
const takerAssetAmount = new BigNumber(10);
@@ -830,10 +821,7 @@ describe('Exchange core', () => {
assetDataUtils.encodeERC20AssetData(erc20TokenA.address),
assetDataUtils.encodeERC20AssetData(erc20TokenB.address),
];
- const makerAssetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(
- makerAmounts,
- makerNestedAssetData,
- );
+ const makerAssetData = assetDataUtils.encodeMultiAssetData(makerAmounts, makerNestedAssetData);
const makerAssetAmount = new BigNumber(1);
const takerAmounts = [new BigNumber(10), new BigNumber(1)];
const takerAssetId = erc721TakerAssetIds[0];
@@ -841,10 +829,7 @@ describe('Exchange core', () => {
assetDataUtils.encodeERC20AssetData(zrxToken.address),
assetDataUtils.encodeERC721AssetData(erc721Token.address, takerAssetId),
];
- const takerAssetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(
- takerAmounts,
- takerNestedAssetData,
- );
+ const takerAssetData = assetDataUtils.encodeMultiAssetData(takerAmounts, takerNestedAssetData);
const takerAssetAmount = new BigNumber(1);
signedOrder = await orderFactory.newSignedOrderAsync({
makerAssetData,
@@ -900,10 +885,7 @@ describe('Exchange core', () => {
assetDataUtils.encodeERC20AssetData(erc20TokenA.address),
assetDataUtils.encodeERC20AssetData(erc20TokenB.address),
];
- const makerAssetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(
- makerAmounts,
- makerNestedAssetData,
- );
+ const makerAssetData = assetDataUtils.encodeMultiAssetData(makerAmounts, makerNestedAssetData);
const makerAssetAmount = new BigNumber(30);
const takerAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address);
const takerAssetAmount = new BigNumber(10);
@@ -980,10 +962,7 @@ describe('Exchange core', () => {
assetDataUtils.encodeERC20AssetData(erc20TokenA.address),
assetDataUtils.encodeERC20AssetData(erc20TokenB.address),
];
- const takerAssetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(
- takerAmounts,
- takerNestedAssetData,
- );
+ const takerAssetData = assetDataUtils.encodeMultiAssetData(takerAmounts, takerNestedAssetData);
const takerAssetAmount = new BigNumber(30);
const makerAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address);
const makerAssetAmount = new BigNumber(10);
diff --git a/contracts/protocol/tsconfig.json b/contracts/protocol/tsconfig.json
index 989d3ef2b..db872fc32 100644
--- a/contracts/protocol/tsconfig.json
+++ b/contracts/protocol/tsconfig.json
@@ -13,7 +13,6 @@
"./generated-artifacts/Exchange.json",
"./generated-artifacts/MixinAuthorizable.json",
"./generated-artifacts/MultiAssetProxy.json",
- "./generated-artifacts/OrderValidator.json",
"./generated-artifacts/TestAssetProxyDispatcher.json",
"./generated-artifacts/TestAssetProxyOwner.json",
"./generated-artifacts/TestExchangeInternals.json",
diff --git a/contracts/test-utils/src/constants.ts b/contracts/test-utils/src/constants.ts
index d2c3ab512..f631dc81a 100644
--- a/contracts/test-utils/src/constants.ts
+++ b/contracts/test-utils/src/constants.ts
@@ -29,6 +29,7 @@ export const constants = {
MAX_TOKEN_TRANSFERFROM_GAS: 80000,
MAX_TOKEN_APPROVE_GAS: 60000,
MAX_TRANSFER_FROM_GAS: 150000,
+ MAX_MATCH_ORDERS_GAS: 400000,
DUMMY_TOKEN_NAME: '',
DUMMY_TOKEN_SYMBOL: '',
DUMMY_TOKEN_DECIMALS: new BigNumber(18),
diff --git a/contracts/tokens/contracts/tokens/ERC20Token/ERC20Token.sol b/contracts/tokens/contracts/tokens/ERC20Token/ERC20Token.sol
index 725d304df..190eead76 100644
--- a/contracts/tokens/contracts/tokens/ERC20Token/ERC20Token.sol
+++ b/contracts/tokens/contracts/tokens/ERC20Token/ERC20Token.sol
@@ -16,7 +16,7 @@
*/
-pragma solidity 0.4.24;
+pragma solidity ^0.4.24;
import "./IERC20Token.sol";
diff --git a/contracts/tokens/contracts/tokens/ERC20Token/IERC20Token.sol b/contracts/tokens/contracts/tokens/ERC20Token/IERC20Token.sol
index 258d47393..9f9b89585 100644
--- a/contracts/tokens/contracts/tokens/ERC20Token/IERC20Token.sol
+++ b/contracts/tokens/contracts/tokens/ERC20Token/IERC20Token.sol
@@ -16,7 +16,7 @@
*/
-pragma solidity 0.4.24;
+pragma solidity ^0.4.24;
contract IERC20Token {
diff --git a/contracts/tokens/contracts/tokens/ERC20Token/MintableERC20Token.sol b/contracts/tokens/contracts/tokens/ERC20Token/MintableERC20Token.sol
index 58bccb5a1..a66031f03 100644
--- a/contracts/tokens/contracts/tokens/ERC20Token/MintableERC20Token.sol
+++ b/contracts/tokens/contracts/tokens/ERC20Token/MintableERC20Token.sol
@@ -16,7 +16,7 @@
*/
-pragma solidity 0.4.24;
+pragma solidity ^0.4.24;
import "@0x/contracts-utils/contracts/utils/SafeMath/SafeMath.sol";
import "./UnlimitedAllowanceERC20Token.sol";
diff --git a/contracts/tokens/contracts/tokens/ERC20Token/UnlimitedAllowanceERC20Token.sol b/contracts/tokens/contracts/tokens/ERC20Token/UnlimitedAllowanceERC20Token.sol
index 2e5bd4348..869d16147 100644
--- a/contracts/tokens/contracts/tokens/ERC20Token/UnlimitedAllowanceERC20Token.sol
+++ b/contracts/tokens/contracts/tokens/ERC20Token/UnlimitedAllowanceERC20Token.sol
@@ -16,7 +16,7 @@
*/
-pragma solidity 0.4.24;
+pragma solidity ^0.4.24;
import "../ERC20Token/ERC20Token.sol";
diff --git a/contracts/tokens/contracts/tokens/ERC721Token/ERC721Token.sol b/contracts/tokens/contracts/tokens/ERC721Token/ERC721Token.sol
index 600cee1ab..c46bd0af4 100644
--- a/contracts/tokens/contracts/tokens/ERC721Token/ERC721Token.sol
+++ b/contracts/tokens/contracts/tokens/ERC721Token/ERC721Token.sol
@@ -16,7 +16,7 @@
*/
-pragma solidity 0.4.24;
+pragma solidity ^0.4.24;
import "./IERC721Token.sol";
import "./IERC721Receiver.sol";
diff --git a/contracts/tokens/contracts/tokens/ERC721Token/IERC721Receiver.sol b/contracts/tokens/contracts/tokens/ERC721Token/IERC721Receiver.sol
index 8e0e32ab2..c3ad35ede 100644
--- a/contracts/tokens/contracts/tokens/ERC721Token/IERC721Receiver.sol
+++ b/contracts/tokens/contracts/tokens/ERC721Token/IERC721Receiver.sol
@@ -16,7 +16,7 @@
*/
-pragma solidity 0.4.24;
+pragma solidity ^0.4.24;
contract IERC721Receiver {
diff --git a/contracts/tokens/contracts/tokens/ERC721Token/IERC721Token.sol b/contracts/tokens/contracts/tokens/ERC721Token/IERC721Token.sol
index ac992c80d..56a3314df 100644
--- a/contracts/tokens/contracts/tokens/ERC721Token/IERC721Token.sol
+++ b/contracts/tokens/contracts/tokens/ERC721Token/IERC721Token.sol
@@ -16,7 +16,7 @@
*/
-pragma solidity 0.4.24;
+pragma solidity ^0.4.24;
contract IERC721Token {
diff --git a/contracts/tokens/contracts/tokens/ERC721Token/MintableERC721Token.sol b/contracts/tokens/contracts/tokens/ERC721Token/MintableERC721Token.sol
index bc5cd2cc2..27326d857 100644
--- a/contracts/tokens/contracts/tokens/ERC721Token/MintableERC721Token.sol
+++ b/contracts/tokens/contracts/tokens/ERC721Token/MintableERC721Token.sol
@@ -16,7 +16,7 @@
*/
-pragma solidity 0.4.24;
+pragma solidity ^0.4.24;
import "./ERC721Token.sol";
diff --git a/contracts/tokens/contracts/tokens/EtherToken/IEtherToken.sol b/contracts/tokens/contracts/tokens/EtherToken/IEtherToken.sol
index 9e2e68766..32baa3eb0 100644
--- a/contracts/tokens/contracts/tokens/EtherToken/IEtherToken.sol
+++ b/contracts/tokens/contracts/tokens/EtherToken/IEtherToken.sol
@@ -16,7 +16,7 @@
*/
-pragma solidity 0.4.24;
+pragma solidity ^0.4.24;
import "../ERC20Token/IERC20Token.sol";
diff --git a/contracts/tokens/package.json b/contracts/tokens/package.json
index 6f8a366dd..79afc4820 100644
--- a/contracts/tokens/package.json
+++ b/contracts/tokens/package.json
@@ -19,7 +19,8 @@
"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 --require make-promises-safe 'lib/test/**/*.js' --timeout 100000 --bail --exit",
- "compile": "sol-compiler --contracts-dir contracts",
+ "compile": "sol-compiler",
+ "watch": "sol-compiler -w",
"clean": "shx rm -rf lib generated-artifacts generated-wrappers",
"generate_contract_wrappers": "abi-gen --abis ${npm_package_config_abis} --template ../../node_modules/@0x/abi-gen-templates/contract.handlebars --partials '../../node_modules/@0x/abi-gen-templates/partials/**/*.handlebars' --output generated-wrappers --backend ethers",
"lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
diff --git a/contracts/tokens/src/artifacts/index.ts b/contracts/tokens/src/artifacts/index.ts
index 63b808748..977d01c3e 100644
--- a/contracts/tokens/src/artifacts/index.ts
+++ b/contracts/tokens/src/artifacts/index.ts
@@ -22,6 +22,7 @@ import * as UnlimitedAllowanceToken_v1 from '../../generated-artifacts/Unlimited
import * as WETH9 from '../../generated-artifacts/WETH9.json';
import * as ZRXToken from '../../generated-artifacts/ZRXToken.json';
+// tslint:disable:no-unnecessary-type-assertion
export const artifacts = {
DummyERC20Token: DummyERC20Token as ContractArtifact,
DummyMultipleReturnERC20Token: DummyMultipleReturnERC20Token as ContractArtifact,
diff --git a/contracts/utils/contracts/utils/LibBytes/LibBytes.sol b/contracts/utils/contracts/utils/LibBytes/LibBytes.sol
index 369f588ad..4ee6228d5 100644
--- a/contracts/utils/contracts/utils/LibBytes/LibBytes.sol
+++ b/contracts/utils/contracts/utils/LibBytes/LibBytes.sol
@@ -16,7 +16,7 @@
*/
-pragma solidity 0.4.24;
+pragma solidity ^0.4.24;
library LibBytes {
diff --git a/contracts/utils/contracts/utils/Ownable/IOwnable.sol b/contracts/utils/contracts/utils/Ownable/IOwnable.sol
index 5deb13497..c0cbfddfd 100644
--- a/contracts/utils/contracts/utils/Ownable/IOwnable.sol
+++ b/contracts/utils/contracts/utils/Ownable/IOwnable.sol
@@ -1,4 +1,4 @@
-pragma solidity 0.4.24;
+pragma solidity ^0.4.24;
contract IOwnable {
diff --git a/contracts/utils/contracts/utils/Ownable/Ownable.sol b/contracts/utils/contracts/utils/Ownable/Ownable.sol
index 0c830be68..aa74a72d2 100644
--- a/contracts/utils/contracts/utils/Ownable/Ownable.sol
+++ b/contracts/utils/contracts/utils/Ownable/Ownable.sol
@@ -1,4 +1,4 @@
-pragma solidity 0.4.24;
+pragma solidity ^0.4.24;
import "./IOwnable.sol";
diff --git a/contracts/utils/contracts/utils/ReentrancyGuard/ReentrancyGuard.sol b/contracts/utils/contracts/utils/ReentrancyGuard/ReentrancyGuard.sol
index 9f98a7a16..1a02c88a4 100644
--- a/contracts/utils/contracts/utils/ReentrancyGuard/ReentrancyGuard.sol
+++ b/contracts/utils/contracts/utils/ReentrancyGuard/ReentrancyGuard.sol
@@ -16,7 +16,7 @@
*/
-pragma solidity 0.4.24;
+pragma solidity ^0.4.24;
contract ReentrancyGuard {
diff --git a/contracts/utils/contracts/utils/SafeMath/SafeMath.sol b/contracts/utils/contracts/utils/SafeMath/SafeMath.sol
index 2855edb9d..d7a4a603e 100644
--- a/contracts/utils/contracts/utils/SafeMath/SafeMath.sol
+++ b/contracts/utils/contracts/utils/SafeMath/SafeMath.sol
@@ -1,4 +1,4 @@
-pragma solidity 0.4.24;
+pragma solidity ^0.4.24;
contract SafeMath {
diff --git a/contracts/utils/package.json b/contracts/utils/package.json
index a776bdfbb..cf94af0f6 100644
--- a/contracts/utils/package.json
+++ b/contracts/utils/package.json
@@ -19,7 +19,8 @@
"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 --require make-promises-safe 'lib/test/**/*.js' --timeout 100000 --bail --exit",
- "compile": "sol-compiler --contracts-dir contracts",
+ "compile": "sol-compiler",
+ "watch": "sol-compiler -w",
"clean": "shx rm -rf lib generated-artifacts generated-wrappers",
"generate_contract_wrappers": "abi-gen --abis ${npm_package_config_abis} --template ../../node_modules/@0x/abi-gen-templates/contract.handlebars --partials '../../node_modules/@0x/abi-gen-templates/partials/**/*.handlebars' --output generated-wrappers --backend ethers",
"lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",