aboutsummaryrefslogtreecommitdiffstats
path: root/packages/contracts
diff options
context:
space:
mode:
authorAmir Bandeali <abandeali1@gmail.com>2018-08-22 11:43:23 +0800
committerGitHub <noreply@github.com>2018-08-22 11:43:23 +0800
commit80e52464a6fdf9576776214f77e46d441b959b06 (patch)
tree964c5c3cb0eeacf70bece4e485b5fddceea2adb4 /packages/contracts
parentf53157414f144a7ea8c24126c9d75d3168228130 (diff)
parent3760eb5bafcc0980b3a42dd5f10e745390702b16 (diff)
downloaddexon-sol-tools-80e52464a6fdf9576776214f77e46d441b959b06.tar
dexon-sol-tools-80e52464a6fdf9576776214f77e46d441b959b06.tar.gz
dexon-sol-tools-80e52464a6fdf9576776214f77e46d441b959b06.tar.bz2
dexon-sol-tools-80e52464a6fdf9576776214f77e46d441b959b06.tar.lz
dexon-sol-tools-80e52464a6fdf9576776214f77e46d441b959b06.tar.xz
dexon-sol-tools-80e52464a6fdf9576776214f77e46d441b959b06.tar.zst
dexon-sol-tools-80e52464a6fdf9576776214f77e46d441b959b06.zip
Merge pull request #985 from 0xProject/feature/contracts/orderValidator
[contracts] Add contract for batch validating orders
Diffstat (limited to 'packages/contracts')
-rw-r--r--packages/contracts/compiler.json1
-rw-r--r--packages/contracts/package.json2
-rw-r--r--packages/contracts/src/2.0.0/extensions/Forwarder/Forwarder.sol (renamed from packages/contracts/src/2.0.0/forwarder/Forwarder.sol)0
-rw-r--r--packages/contracts/src/2.0.0/extensions/Forwarder/MixinAssets.sol (renamed from packages/contracts/src/2.0.0/forwarder/MixinAssets.sol)10
-rw-r--r--packages/contracts/src/2.0.0/extensions/Forwarder/MixinExchangeWrapper.sol (renamed from packages/contracts/src/2.0.0/forwarder/MixinExchangeWrapper.sol)8
-rw-r--r--packages/contracts/src/2.0.0/extensions/Forwarder/MixinForwarderCore.sol (renamed from packages/contracts/src/2.0.0/forwarder/MixinForwarderCore.sol)8
-rw-r--r--packages/contracts/src/2.0.0/extensions/Forwarder/MixinWeth.sol (renamed from packages/contracts/src/2.0.0/forwarder/MixinWeth.sol)2
-rw-r--r--packages/contracts/src/2.0.0/extensions/Forwarder/interfaces/IAssets.sol (renamed from packages/contracts/src/2.0.0/forwarder/interfaces/IAssets.sol)0
-rw-r--r--packages/contracts/src/2.0.0/extensions/Forwarder/interfaces/IForwarder.sol (renamed from packages/contracts/src/2.0.0/forwarder/interfaces/IForwarder.sol)0
-rw-r--r--packages/contracts/src/2.0.0/extensions/Forwarder/interfaces/IForwarderCore.sol (renamed from packages/contracts/src/2.0.0/forwarder/interfaces/IForwarderCore.sol)4
-rw-r--r--packages/contracts/src/2.0.0/extensions/Forwarder/libs/LibConstants.sol (renamed from packages/contracts/src/2.0.0/forwarder/libs/LibConstants.sol)8
-rw-r--r--packages/contracts/src/2.0.0/extensions/Forwarder/libs/LibForwarderErrors.sol (renamed from packages/contracts/src/2.0.0/forwarder/libs/LibForwarderErrors.sol)2
-rw-r--r--packages/contracts/src/2.0.0/extensions/Forwarder/mixins/MAssets.sol (renamed from packages/contracts/src/2.0.0/forwarder/mixins/MAssets.sol)0
-rw-r--r--packages/contracts/src/2.0.0/extensions/Forwarder/mixins/MExchangeWrapper.sol (renamed from packages/contracts/src/2.0.0/forwarder/mixins/MExchangeWrapper.sol)4
-rw-r--r--packages/contracts/src/2.0.0/extensions/Forwarder/mixins/MWeth.sol (renamed from packages/contracts/src/2.0.0/forwarder/mixins/MWeth.sol)0
-rw-r--r--packages/contracts/src/2.0.0/extensions/OrderValidator/OrderValidator.sol218
-rw-r--r--packages/contracts/test/extensions/forwarder.ts (renamed from packages/contracts/test/forwarder/forwarder.ts)0
-rw-r--r--packages/contracts/test/extensions/order_validator.ts600
-rw-r--r--packages/contracts/test/utils/artifacts.ts2
19 files changed, 845 insertions, 24 deletions
diff --git a/packages/contracts/compiler.json b/packages/contracts/compiler.json
index 09c47e6af..16524231c 100644
--- a/packages/contracts/compiler.json
+++ b/packages/contracts/compiler.json
@@ -39,6 +39,7 @@
"MixinAuthorizable",
"MultiSigWallet",
"MultiSigWalletWithTimeLock",
+ "OrderValidator",
"TestAssetProxyOwner",
"TestAssetProxyDispatcher",
"TestConstants",
diff --git a/packages/contracts/package.json b/packages/contracts/package.json
index b25b33c20..81014537f 100644
--- a/packages/contracts/package.json
+++ b/packages/contracts/package.json
@@ -37,7 +37,7 @@
},
"config": {
"abis":
- "../migrations/artifacts/2.0.0/@(AssetProxyOwner|DummyERC20Token|DummyERC721Receiver|DummyERC721Token|DummyNoReturnERC20Token|ERC20Proxy|ERC721Proxy|Forwarder|Exchange|ExchangeWrapper|IAssetData|IAssetProxy|InvalidERC721Receiver|MixinAuthorizable|MultiSigWallet|MultiSigWalletWithTimeLock|TestAssetProxyOwner|TestAssetProxyDispatcher|TestConstants|TestExchangeInternals|TestLibBytes|TestLibs|TestSignatureValidator|Validator|Wallet|TokenRegistry|Whitelist|WETH9|ZRXToken).json"
+ "../migrations/artifacts/2.0.0/@(AssetProxyOwner|DummyERC20Token|DummyERC721Receiver|DummyERC721Token|DummyNoReturnERC20Token|ERC20Proxy|ERC721Proxy|Forwarder|Exchange|ExchangeWrapper|IAssetData|IAssetProxy|InvalidERC721Receiver|MixinAuthorizable|MultiSigWallet|MultiSigWalletWithTimeLock|OrderValidator|TestAssetProxyOwner|TestAssetProxyDispatcher|TestConstants|TestExchangeInternals|TestLibBytes|TestLibs|TestSignatureValidator|Validator|Wallet|TokenRegistry|Whitelist|WETH9|ZRXToken).json"
},
"repository": {
"type": "git",
diff --git a/packages/contracts/src/2.0.0/forwarder/Forwarder.sol b/packages/contracts/src/2.0.0/extensions/Forwarder/Forwarder.sol
index 6b17bb29b..6b17bb29b 100644
--- a/packages/contracts/src/2.0.0/forwarder/Forwarder.sol
+++ b/packages/contracts/src/2.0.0/extensions/Forwarder/Forwarder.sol
diff --git a/packages/contracts/src/2.0.0/forwarder/MixinAssets.sol b/packages/contracts/src/2.0.0/extensions/Forwarder/MixinAssets.sol
index e06f9a8e3..d6a38aa6e 100644
--- a/packages/contracts/src/2.0.0/forwarder/MixinAssets.sol
+++ b/packages/contracts/src/2.0.0/extensions/Forwarder/MixinAssets.sol
@@ -18,10 +18,10 @@
pragma solidity 0.4.24;
-import "../utils/LibBytes/LibBytes.sol";
-import "../utils/Ownable/Ownable.sol";
-import "../tokens/ERC20Token/IERC20Token.sol";
-import "../tokens/ERC721Token/IERC721Token.sol";
+import "../../utils/LibBytes/LibBytes.sol";
+import "../../utils/Ownable/Ownable.sol";
+import "../../tokens/ERC20Token/IERC20Token.sol";
+import "../../tokens/ERC721Token/IERC721Token.sol";
import "./libs/LibConstants.sol";
import "./mixins/MAssets.sol";
@@ -67,7 +67,7 @@ contract MixinAssets is
} else if (proxyId == ERC721_DATA_ID) {
transferERC721Token(assetData, amount);
} else {
- revert("UNSUPPORTED_TOKEN_PROXY");
+ revert("UNSUPPORTED_ASSET_PROXY");
}
}
diff --git a/packages/contracts/src/2.0.0/forwarder/MixinExchangeWrapper.sol b/packages/contracts/src/2.0.0/extensions/Forwarder/MixinExchangeWrapper.sol
index 4584bb840..218713d3c 100644
--- a/packages/contracts/src/2.0.0/forwarder/MixinExchangeWrapper.sol
+++ b/packages/contracts/src/2.0.0/extensions/Forwarder/MixinExchangeWrapper.sol
@@ -21,10 +21,10 @@ pragma experimental ABIEncoderV2;
import "./libs/LibConstants.sol";
import "./mixins/MExchangeWrapper.sol";
-import "../protocol/Exchange/libs/LibAbiEncoder.sol";
-import "../protocol/Exchange/libs/LibOrder.sol";
-import "../protocol/Exchange/libs/LibFillResults.sol";
-import "../protocol/Exchange/libs/LibMath.sol";
+import "../../protocol/Exchange/libs/LibAbiEncoder.sol";
+import "../../protocol/Exchange/libs/LibOrder.sol";
+import "../../protocol/Exchange/libs/LibFillResults.sol";
+import "../../protocol/Exchange/libs/LibMath.sol";
contract MixinExchangeWrapper is
diff --git a/packages/contracts/src/2.0.0/forwarder/MixinForwarderCore.sol b/packages/contracts/src/2.0.0/extensions/Forwarder/MixinForwarderCore.sol
index 93cbf79be..42cec4d36 100644
--- a/packages/contracts/src/2.0.0/forwarder/MixinForwarderCore.sol
+++ b/packages/contracts/src/2.0.0/extensions/Forwarder/MixinForwarderCore.sol
@@ -24,10 +24,10 @@ import "./mixins/MWeth.sol";
import "./mixins/MAssets.sol";
import "./mixins/MExchangeWrapper.sol";
import "./interfaces/IForwarderCore.sol";
-import "../utils/LibBytes/LibBytes.sol";
-import "../protocol/Exchange/libs/LibOrder.sol";
-import "../protocol/Exchange/libs/LibFillResults.sol";
-import "../protocol/Exchange/libs/LibMath.sol";
+import "../../utils/LibBytes/LibBytes.sol";
+import "../../protocol/Exchange/libs/LibOrder.sol";
+import "../../protocol/Exchange/libs/LibFillResults.sol";
+import "../../protocol/Exchange/libs/LibMath.sol";
contract MixinForwarderCore is
diff --git a/packages/contracts/src/2.0.0/forwarder/MixinWeth.sol b/packages/contracts/src/2.0.0/extensions/Forwarder/MixinWeth.sol
index e07940776..93e85e599 100644
--- a/packages/contracts/src/2.0.0/forwarder/MixinWeth.sol
+++ b/packages/contracts/src/2.0.0/extensions/Forwarder/MixinWeth.sol
@@ -18,7 +18,7 @@
pragma solidity 0.4.24;
-import "../protocol/Exchange/libs/LibMath.sol";
+import "../../protocol/Exchange/libs/LibMath.sol";
import "./libs/LibConstants.sol";
import "./mixins/MWeth.sol";
diff --git a/packages/contracts/src/2.0.0/forwarder/interfaces/IAssets.sol b/packages/contracts/src/2.0.0/extensions/Forwarder/interfaces/IAssets.sol
index 1e034c003..1e034c003 100644
--- a/packages/contracts/src/2.0.0/forwarder/interfaces/IAssets.sol
+++ b/packages/contracts/src/2.0.0/extensions/Forwarder/interfaces/IAssets.sol
diff --git a/packages/contracts/src/2.0.0/forwarder/interfaces/IForwarder.sol b/packages/contracts/src/2.0.0/extensions/Forwarder/interfaces/IForwarder.sol
index f5a26e2ba..f5a26e2ba 100644
--- a/packages/contracts/src/2.0.0/forwarder/interfaces/IForwarder.sol
+++ b/packages/contracts/src/2.0.0/extensions/Forwarder/interfaces/IForwarder.sol
diff --git a/packages/contracts/src/2.0.0/forwarder/interfaces/IForwarderCore.sol b/packages/contracts/src/2.0.0/extensions/Forwarder/interfaces/IForwarderCore.sol
index 3ecbb133b..74c7da01d 100644
--- a/packages/contracts/src/2.0.0/forwarder/interfaces/IForwarderCore.sol
+++ b/packages/contracts/src/2.0.0/extensions/Forwarder/interfaces/IForwarderCore.sol
@@ -19,8 +19,8 @@
pragma solidity 0.4.24;
pragma experimental ABIEncoderV2;
-import "../../protocol/Exchange/libs/LibOrder.sol";
-import "../../protocol/Exchange/libs/LibFillResults.sol";
+import "../../../protocol/Exchange/libs/LibOrder.sol";
+import "../../../protocol/Exchange/libs/LibFillResults.sol";
contract IForwarderCore {
diff --git a/packages/contracts/src/2.0.0/forwarder/libs/LibConstants.sol b/packages/contracts/src/2.0.0/extensions/Forwarder/libs/LibConstants.sol
index fb9691fe8..704e42ce3 100644
--- a/packages/contracts/src/2.0.0/forwarder/libs/LibConstants.sol
+++ b/packages/contracts/src/2.0.0/extensions/Forwarder/libs/LibConstants.sol
@@ -18,10 +18,10 @@
pragma solidity 0.4.24;
-import "../../utils/LibBytes/LibBytes.sol";
-import "../../protocol/Exchange/interfaces/IExchange.sol";
-import "../../tokens/EtherToken/IEtherToken.sol";
-import "../../tokens/ERC20Token/IERC20Token.sol";
+import "../../../utils/LibBytes/LibBytes.sol";
+import "../../../protocol/Exchange/interfaces/IExchange.sol";
+import "../../../tokens/EtherToken/IEtherToken.sol";
+import "../../../tokens/ERC20Token/IERC20Token.sol";
contract LibConstants {
diff --git a/packages/contracts/src/2.0.0/forwarder/libs/LibForwarderErrors.sol b/packages/contracts/src/2.0.0/extensions/Forwarder/libs/LibForwarderErrors.sol
index cdfb77a0b..fb3ade1db 100644
--- a/packages/contracts/src/2.0.0/forwarder/libs/LibForwarderErrors.sol
+++ b/packages/contracts/src/2.0.0/extensions/Forwarder/libs/LibForwarderErrors.sol
@@ -27,7 +27,7 @@ contract LibForwarderErrors {
string constant OVERSOLD_WETH = "OVERSOLD_WETH"; // More WETH sold than provided with current message call.
string constant COMPLETE_FILL_FAILED = "COMPLETE_FILL_FAILED"; // Desired purchase amount not completely filled (required for ZRX fees only).
string constant TRANSFER_FAILED = "TRANSFER_FAILED"; // Asset transfer failed.
- string constant UNSUPPORTED_TOKEN_PROXY = "UNSUPPORTED_TOKEN_PROXY"; // Proxy in assetData not supported.
+ string constant UNSUPPORTED_ASSET_PROXY = "UNSUPPORTED_ASSET_PROXY"; // Proxy in assetData not supported.
string constant DEFAULT_FUNCTION_WETH_CONTRACT_ONLY = "DEFAULT_FUNCTION_WETH_CONTRACT_ONLY"; // Fallback function may only be used for WETH withdrawals.
string constant INVALID_MSG_VALUE = "INVALID_MSG_VALUE"; // msg.value must be greater than 0.
string constant INVALID_AMOUNT = "INVALID_AMOUNT"; // Amount must equal 1.
diff --git a/packages/contracts/src/2.0.0/forwarder/mixins/MAssets.sol b/packages/contracts/src/2.0.0/extensions/Forwarder/mixins/MAssets.sol
index 83636432a..83636432a 100644
--- a/packages/contracts/src/2.0.0/forwarder/mixins/MAssets.sol
+++ b/packages/contracts/src/2.0.0/extensions/Forwarder/mixins/MAssets.sol
diff --git a/packages/contracts/src/2.0.0/forwarder/mixins/MExchangeWrapper.sol b/packages/contracts/src/2.0.0/extensions/Forwarder/mixins/MExchangeWrapper.sol
index 360dea0e4..13c26b03a 100644
--- a/packages/contracts/src/2.0.0/forwarder/mixins/MExchangeWrapper.sol
+++ b/packages/contracts/src/2.0.0/extensions/Forwarder/mixins/MExchangeWrapper.sol
@@ -19,8 +19,8 @@
pragma solidity 0.4.24;
pragma experimental ABIEncoderV2;
-import "../../protocol/Exchange/libs/LibOrder.sol";
-import "../../protocol/Exchange/libs/LibFillResults.sol";
+import "../../../protocol/Exchange/libs/LibOrder.sol";
+import "../../../protocol/Exchange/libs/LibFillResults.sol";
contract MExchangeWrapper {
diff --git a/packages/contracts/src/2.0.0/forwarder/mixins/MWeth.sol b/packages/contracts/src/2.0.0/extensions/Forwarder/mixins/MWeth.sol
index 88e77be4e..88e77be4e 100644
--- a/packages/contracts/src/2.0.0/forwarder/mixins/MWeth.sol
+++ b/packages/contracts/src/2.0.0/extensions/Forwarder/mixins/MWeth.sol
diff --git a/packages/contracts/src/2.0.0/extensions/OrderValidator/OrderValidator.sol b/packages/contracts/src/2.0.0/extensions/OrderValidator/OrderValidator.sol
new file mode 100644
index 000000000..a18345245
--- /dev/null
+++ b/packages/contracts/src/2.0.0/extensions/OrderValidator/OrderValidator.sol
@@ -0,0 +1,218 @@
+/*
+
+ 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 "../../protocol/Exchange/interfaces/IExchange.sol";
+import "../../protocol/Exchange/libs/LibOrder.sol";
+import "../../tokens/ERC20Token/IERC20Token.sol";
+import "../../tokens/ERC721Token/IERC721Token.sol";
+import "../../utils/LibBytes/LibBytes.sol";
+
+
+contract OrderValidator {
+
+ bytes4 constant internal ERC20_DATA_ID = bytes4(keccak256("ERC20Token(address)"));
+ bytes4 constant internal ERC721_DATA_ID = bytes4(keccak256("ERC721Token(address,uint256)"));
+
+ using LibBytes for bytes;
+
+ struct TraderInfo {
+ uint256 makerBalance; // Maker's balance of makerAsset
+ uint256 makerAllowance; // Maker's allowance to corresponding AssetProxy
+ uint256 takerBalance; // Taker's balance of takerAsset
+ uint256 takerAllowance; // Taker's allowance to corresponding AssetProxy
+ uint256 makerZrxBalance; // Maker's balance of ZRX
+ uint256 makerZrxAllowance; // Maker's allowance of ZRX to ERC20Proxy
+ uint256 takerZrxBalance; // Taker's balance of ZRX
+ uint256 takerZrxAllowance; // Taker's allowance of ZRX to ERC20Proxy
+ }
+
+ // solhint-disable var-name-mixedcase
+ IExchange internal EXCHANGE;
+ bytes internal ZRX_ASSET_DATA;
+ // solhint-enable var-name-mixedcase
+
+ constructor (address _exchange, bytes memory _zrxAssetData)
+ public
+ {
+ EXCHANGE = IExchange(_exchange);
+ ZRX_ASSET_DATA = _zrxAssetData;
+ }
+
+ /// @dev Fetches information for order and maker/taker of order.
+ /// @param order The order structure.
+ /// @param takerAddress Address that will be filling the order.
+ /// @return OrderInfo and TraderInfo instances for given order.
+ function getOrderAndTraderInfo(LibOrder.Order memory order, address takerAddress)
+ public
+ view
+ returns (LibOrder.OrderInfo memory orderInfo, TraderInfo memory traderInfo)
+ {
+ orderInfo = EXCHANGE.getOrderInfo(order);
+ traderInfo = getTraderInfo(order, takerAddress);
+ return (orderInfo, traderInfo);
+ }
+
+ /// @dev Fetches information for all passed in orders and the makers/takers of each order.
+ /// @param orders Array of order specifications.
+ /// @param takerAddresses Array of taker addresses corresponding to each order.
+ /// @return Arrays of OrderInfo and TraderInfo instances that correspond to each order.
+ function getOrdersAndTradersInfo(LibOrder.Order[] memory orders, address[] memory takerAddresses)
+ public
+ view
+ returns (LibOrder.OrderInfo[] memory ordersInfo, TraderInfo[] memory tradersInfo)
+ {
+ ordersInfo = EXCHANGE.getOrdersInfo(orders);
+ tradersInfo = getTradersInfo(orders, takerAddresses);
+ return (ordersInfo, tradersInfo);
+ }
+
+ /// @dev Fetches balance and allowances for maker and taker of order.
+ /// @param order The order structure.
+ /// @param takerAddress Address that will be filling the order.
+ /// @return Balances and allowances of maker and taker of order.
+ function getTraderInfo(LibOrder.Order memory order, address takerAddress)
+ public
+ view
+ returns (TraderInfo memory traderInfo)
+ {
+ (traderInfo.makerBalance, traderInfo.makerAllowance) = getBalanceAndAllowance(order.makerAddress, order.makerAssetData);
+ (traderInfo.takerBalance, traderInfo.takerAllowance) = getBalanceAndAllowance(takerAddress, order.takerAssetData);
+ bytes memory zrxAssetData = ZRX_ASSET_DATA;
+ (traderInfo.makerZrxBalance, traderInfo.makerZrxAllowance) = getBalanceAndAllowance(order.makerAddress, zrxAssetData);
+ (traderInfo.takerZrxBalance, traderInfo.takerZrxAllowance) = getBalanceAndAllowance(takerAddress, zrxAssetData);
+ return traderInfo;
+ }
+
+ /// @dev Fetches balances and allowances of maker and taker for each provided order.
+ /// @param orders Array of order specifications.
+ /// @param takerAddresses Array of taker addresses corresponding to each order.
+ /// @return Array of balances and allowances for maker and taker of each order.
+ function getTradersInfo(LibOrder.Order[] memory orders, address[] memory takerAddresses)
+ public
+ view
+ returns (TraderInfo[] memory)
+ {
+ uint256 ordersLength = orders.length;
+ TraderInfo[] memory tradersInfo = new TraderInfo[](ordersLength);
+ for (uint256 i = 0; i != ordersLength; i++) {
+ tradersInfo[i] = getTraderInfo(orders[i], takerAddresses[i]);
+ }
+ return tradersInfo;
+ }
+
+ /// @dev Fetches token balances and allowances of an address to given assetProxy. Supports ERC20 and ERC721.
+ /// @param target Address to fetch balances and allowances of.
+ /// @param assetData Encoded data that can be decoded by a specified proxy contract when transferring asset.
+ /// @return Balance of asset and allowance set to given proxy of asset.
+ /// For ERC721 tokens, these values will always be 1 or 0.
+ function getBalanceAndAllowance(address target, bytes memory assetData)
+ public
+ view
+ returns (uint256 balance, uint256 allowance)
+ {
+ bytes4 assetProxyId = assetData.readBytes4(0);
+ address token = assetData.readAddress(16);
+ address assetProxy = EXCHANGE.getAssetProxy(assetProxyId);
+
+ if (assetProxyId == ERC20_DATA_ID) {
+ // Query balance
+ balance = IERC20Token(token).balanceOf(target);
+
+ // Query allowance
+ allowance = IERC20Token(token).allowance(target, assetProxy);
+ } else if (assetProxyId == ERC721_DATA_ID) {
+ uint256 tokenId = assetData.readUint256(36);
+
+ // Query owner of tokenId
+ address owner = getERC721TokenOwner(token, tokenId);
+
+ // Set balance to 1 if tokenId is owned by target
+ balance = target == owner ? 1 : 0;
+
+ // Check if ERC721Proxy is approved to spend tokenId
+ bool isApproved = IERC721Token(token).isApprovedForAll(target, assetProxy) || IERC721Token(token).getApproved(tokenId) == assetProxy;
+
+ // Set alowance to 1 if ERC721Proxy is approved to spend tokenId
+ allowance = isApproved ? 1 : 0;
+ } else {
+ revert("UNSUPPORTED_ASSET_PROXY");
+ }
+ return (balance, allowance);
+ }
+
+ /// @dev Fetches token balances and allowances of an address for each given assetProxy. Supports ERC20 and ERC721.
+ /// @param target Address to fetch balances and allowances of.
+ /// @param assetData Array of encoded byte arrays that can be decoded by a specified proxy contract when transferring asset.
+ /// @return Balances and allowances of assets.
+ /// For ERC721 tokens, these values will always be 1 or 0.
+ function getBalancesAndAllowances(address target, bytes[] memory assetData)
+ public
+ view
+ returns (uint256[] memory, uint256[] memory)
+ {
+ uint256 length = assetData.length;
+ uint256[] memory balances = new uint256[](length);
+ uint256[] memory allowances = new uint256[](length);
+ for (uint256 i = 0; i != length; i++) {
+ (balances[i], allowances[i]) = getBalanceAndAllowance(target, assetData[i]);
+ }
+ return (balances, allowances);
+ }
+
+ /// @dev Calls `token.ownerOf(tokenId)`, but returns a null owner instead of reverting on an unowned token.
+ /// @param token Address of ERC721 token.
+ /// @param tokenId The identifier for the specific NFT.
+ /// @return Owner of tokenId or null address if unowned.
+ function getERC721TokenOwner(address token, uint256 tokenId)
+ public
+ view
+ returns (address owner)
+ {
+ assembly {
+ // load free memory pointer
+ let cdStart := mload(64)
+
+ // bytes4(keccak256(ownerOf(uint256))) = 0x6352211e
+ mstore(cdStart, 0x6352211e00000000000000000000000000000000000000000000000000000000)
+ mstore(add(cdStart, 4), tokenId)
+
+ // staticcall `ownerOf(tokenId)`
+ // `ownerOf` will revert if tokenId is not owned
+ let success := staticcall(
+ gas, // forward all gas
+ token, // call token contract
+ cdStart, // start of calldata
+ 36, // length of input is 36 bytes
+ cdStart, // write output over input
+ 32 // size of output is 32 bytes
+ )
+
+ // Success implies that tokenId is owned
+ // Copy owner from return data if successful
+ if success {
+ owner := mload(cdStart)
+ }
+ }
+
+ // Owner initialized to address(0), no need to modify if call is unsuccessful
+ return owner;
+ }
+}
diff --git a/packages/contracts/test/forwarder/forwarder.ts b/packages/contracts/test/extensions/forwarder.ts
index 18101d684..18101d684 100644
--- a/packages/contracts/test/forwarder/forwarder.ts
+++ b/packages/contracts/test/extensions/forwarder.ts
diff --git a/packages/contracts/test/extensions/order_validator.ts b/packages/contracts/test/extensions/order_validator.ts
new file mode 100644
index 000000000..3a57cfc37
--- /dev/null
+++ b/packages/contracts/test/extensions/order_validator.ts
@@ -0,0 +1,600 @@
+import { BlockchainLifecycle } from '@0xproject/dev-utils';
+import { assetDataUtils, orderHashUtils } from '@0xproject/order-utils';
+import { SignedOrder } from '@0xproject/types';
+import { BigNumber } from '@0xproject/utils';
+import * as chai from 'chai';
+import * as _ from 'lodash';
+
+import { DummyERC20TokenContract } from '../../generated_contract_wrappers/dummy_erc20_token';
+import { DummyERC721TokenContract } from '../../generated_contract_wrappers/dummy_erc721_token';
+import { ERC20ProxyContract } from '../../generated_contract_wrappers/erc20_proxy';
+import { ERC721ProxyContract } from '../../generated_contract_wrappers/erc721_proxy';
+import { ExchangeContract } from '../../generated_contract_wrappers/exchange';
+import { OrderValidatorContract } from '../../generated_contract_wrappers/order_validator';
+import { artifacts } from '../utils/artifacts';
+import { chaiSetup } from '../utils/chai_setup';
+import { constants } from '../utils/constants';
+import { ERC20Wrapper } from '../utils/erc20_wrapper';
+import { ERC721Wrapper } from '../utils/erc721_wrapper';
+import { ExchangeWrapper } from '../utils/exchange_wrapper';
+import { OrderFactory } from '../utils/order_factory';
+import { OrderStatus } from '../utils/types';
+import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper';
+
+chaiSetup.configure();
+const expect = chai.expect;
+const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
+
+describe('OrderValidator', () => {
+ let makerAddress: string;
+ let owner: string;
+ let takerAddress: string;
+ let erc20AssetData: string;
+ let erc721AssetData: string;
+
+ let erc20Token: DummyERC20TokenContract;
+ let zrxToken: DummyERC20TokenContract;
+ let erc721Token: DummyERC721TokenContract;
+ let exchange: ExchangeContract;
+ let orderValidator: OrderValidatorContract;
+ let erc20Proxy: ERC20ProxyContract;
+ let erc721Proxy: ERC721ProxyContract;
+
+ let signedOrder: SignedOrder;
+ let signedOrder2: SignedOrder;
+ let orderFactory: OrderFactory;
+
+ const tokenId = new BigNumber(123456789);
+ const tokenId2 = new BigNumber(987654321);
+ const ERC721_BALANCE = new BigNumber(1);
+ const ERC721_ALLOWANCE = new BigNumber(1);
+
+ before(async () => {
+ await blockchainLifecycle.startAsync();
+ });
+ after(async () => {
+ await blockchainLifecycle.revertAsync();
+ });
+
+ before(async () => {
+ const accounts = await web3Wrapper.getAvailableAddressesAsync();
+ const usedAddresses = ([owner, makerAddress, takerAddress] = _.slice(accounts, 0, 3));
+
+ const erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner);
+ const erc721Wrapper = new ERC721Wrapper(provider, usedAddresses, owner);
+
+ const numDummyErc20ToDeploy = 2;
+ [erc20Token, zrxToken] = await erc20Wrapper.deployDummyTokensAsync(
+ numDummyErc20ToDeploy,
+ constants.DUMMY_TOKEN_DECIMALS,
+ );
+ erc20Proxy = await erc20Wrapper.deployProxyAsync();
+
+ [erc721Token] = await erc721Wrapper.deployDummyTokensAsync();
+ erc721Proxy = await erc721Wrapper.deployProxyAsync();
+
+ const zrxAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address);
+ exchange = await ExchangeContract.deployFrom0xArtifactAsync(
+ artifacts.Exchange,
+ provider,
+ txDefaults,
+ zrxAssetData,
+ );
+ const exchangeWrapper = new ExchangeWrapper(exchange, provider);
+ await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner);
+ await exchangeWrapper.registerAssetProxyAsync(erc721Proxy.address, owner);
+
+ orderValidator = await OrderValidatorContract.deployFrom0xArtifactAsync(
+ artifacts.OrderValidator,
+ provider,
+ txDefaults,
+ exchange.address,
+ zrxAssetData,
+ );
+
+ erc20AssetData = assetDataUtils.encodeERC20AssetData(erc20Token.address);
+ erc721AssetData = assetDataUtils.encodeERC721AssetData(erc721Token.address, tokenId);
+ const defaultOrderParams = {
+ ...constants.STATIC_ORDER_PARAMS,
+ exchangeAddress: exchange.address,
+ makerAddress,
+ feeRecipientAddress: constants.NULL_ADDRESS,
+ makerAssetData: erc20AssetData,
+ takerAssetData: erc721AssetData,
+ };
+ const privateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddress)];
+ orderFactory = new OrderFactory(privateKey, defaultOrderParams);
+ });
+
+ beforeEach(async () => {
+ await blockchainLifecycle.startAsync();
+ });
+ afterEach(async () => {
+ await blockchainLifecycle.revertAsync();
+ });
+
+ describe('getBalanceAndAllowance', () => {
+ describe('getERC721TokenOwner', async () => {
+ it('should return the null address when tokenId is not owned', async () => {
+ const tokenOwner = await orderValidator.getERC721TokenOwner.callAsync(makerAddress, tokenId);
+ expect(tokenOwner).to.be.equal(constants.NULL_ADDRESS);
+ });
+ it('should return the owner address when tokenId is owned', async () => {
+ await web3Wrapper.awaitTransactionSuccessAsync(
+ await erc721Token.mint.sendTransactionAsync(makerAddress, tokenId),
+ constants.AWAIT_TRANSACTION_MINED_MS,
+ );
+ const tokenOwner = await orderValidator.getERC721TokenOwner.callAsync(erc721Token.address, tokenId);
+ expect(tokenOwner).to.be.equal(makerAddress);
+ });
+ });
+ describe('ERC20 assetData', () => {
+ it('should return the correct balances and allowances when both values are 0', async () => {
+ const [newBalance, newAllowance] = await orderValidator.getBalanceAndAllowance.callAsync(
+ makerAddress,
+ erc20AssetData,
+ );
+ expect(constants.ZERO_AMOUNT).to.be.bignumber.equal(newBalance);
+ expect(constants.ZERO_AMOUNT).to.be.bignumber.equal(newAllowance);
+ });
+ it('should return the correct balance and allowance when both values are non-zero', async () => {
+ const balance = new BigNumber(123);
+ const allowance = new BigNumber(456);
+ await web3Wrapper.awaitTransactionSuccessAsync(
+ await erc20Token.setBalance.sendTransactionAsync(makerAddress, balance),
+ constants.AWAIT_TRANSACTION_MINED_MS,
+ );
+ await web3Wrapper.awaitTransactionSuccessAsync(
+ await erc20Token.approve.sendTransactionAsync(erc20Proxy.address, allowance, {
+ from: makerAddress,
+ }),
+ constants.AWAIT_TRANSACTION_MINED_MS,
+ );
+ const [newBalance, newAllowance] = await orderValidator.getBalanceAndAllowance.callAsync(
+ makerAddress,
+ erc20AssetData,
+ );
+ expect(balance).to.be.bignumber.equal(newBalance);
+ expect(allowance).to.be.bignumber.equal(newAllowance);
+ });
+ });
+ describe('ERC721 assetData', () => {
+ it('should return a balance of 0 when the tokenId is not owned by target', async () => {
+ const [newBalance] = await orderValidator.getBalanceAndAllowance.callAsync(
+ makerAddress,
+ erc721AssetData,
+ );
+ expect(newBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ });
+ it('should return an allowance of 0 when no approval is set', async () => {
+ const [, newAllowance] = await orderValidator.getBalanceAndAllowance.callAsync(
+ makerAddress,
+ erc721AssetData,
+ );
+ expect(newAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ });
+ it('should return a balance of 1 when the tokenId is owned by target', async () => {
+ await web3Wrapper.awaitTransactionSuccessAsync(
+ await erc721Token.mint.sendTransactionAsync(makerAddress, tokenId),
+ constants.AWAIT_TRANSACTION_MINED_MS,
+ );
+ const [newBalance] = await orderValidator.getBalanceAndAllowance.callAsync(
+ makerAddress,
+ erc721AssetData,
+ );
+ expect(newBalance).to.be.bignumber.equal(ERC721_BALANCE);
+ });
+ it('should return an allowance of 1 when ERC721Proxy is approved for all', async () => {
+ const isApproved = true;
+ await web3Wrapper.awaitTransactionSuccessAsync(
+ await erc721Token.setApprovalForAll.sendTransactionAsync(erc721Proxy.address, isApproved, {
+ from: makerAddress,
+ }),
+ constants.AWAIT_TRANSACTION_MINED_MS,
+ );
+ const [, newAllowance] = await orderValidator.getBalanceAndAllowance.callAsync(
+ makerAddress,
+ erc721AssetData,
+ );
+ expect(newAllowance).to.be.bignumber.equal(ERC721_ALLOWANCE);
+ });
+ it('should return an allowance of 1 when ERC721Proxy is approved for specific tokenId', async () => {
+ await web3Wrapper.awaitTransactionSuccessAsync(
+ await erc721Token.mint.sendTransactionAsync(makerAddress, tokenId),
+ constants.AWAIT_TRANSACTION_MINED_MS,
+ );
+ await web3Wrapper.awaitTransactionSuccessAsync(
+ await erc721Token.approve.sendTransactionAsync(erc721Proxy.address, tokenId, {
+ from: makerAddress,
+ }),
+ constants.AWAIT_TRANSACTION_MINED_MS,
+ );
+ const [, newAllowance] = await orderValidator.getBalanceAndAllowance.callAsync(
+ makerAddress,
+ erc721AssetData,
+ );
+ expect(newAllowance).to.be.bignumber.equal(ERC721_ALLOWANCE);
+ });
+ });
+ });
+ describe('getBalancesAndAllowances', () => {
+ it('should return the correct balances and allowances when all values are 0', async () => {
+ const [
+ [erc20Balance, erc721Balance],
+ [erc20Allowance, erc721Allowance],
+ ] = await orderValidator.getBalancesAndAllowances.callAsync(makerAddress, [
+ erc20AssetData,
+ erc721AssetData,
+ ]);
+ expect(erc20Balance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ expect(erc721Balance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ expect(erc20Allowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ expect(erc721Allowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ });
+ it('should return the correct balances and allowances when balances and allowances are non-zero', async () => {
+ const balance = new BigNumber(123);
+ const allowance = new BigNumber(456);
+ await web3Wrapper.awaitTransactionSuccessAsync(
+ await erc20Token.setBalance.sendTransactionAsync(makerAddress, balance),
+ constants.AWAIT_TRANSACTION_MINED_MS,
+ );
+ await web3Wrapper.awaitTransactionSuccessAsync(
+ await erc20Token.approve.sendTransactionAsync(erc20Proxy.address, allowance, {
+ from: makerAddress,
+ }),
+ constants.AWAIT_TRANSACTION_MINED_MS,
+ );
+ await web3Wrapper.awaitTransactionSuccessAsync(
+ await erc721Token.mint.sendTransactionAsync(makerAddress, tokenId),
+ constants.AWAIT_TRANSACTION_MINED_MS,
+ );
+ await web3Wrapper.awaitTransactionSuccessAsync(
+ await erc721Token.approve.sendTransactionAsync(erc721Proxy.address, tokenId, {
+ from: makerAddress,
+ }),
+ constants.AWAIT_TRANSACTION_MINED_MS,
+ );
+ const [
+ [erc20Balance, erc721Balance],
+ [erc20Allowance, erc721Allowance],
+ ] = await orderValidator.getBalancesAndAllowances.callAsync(makerAddress, [
+ erc20AssetData,
+ erc721AssetData,
+ ]);
+ expect(erc20Balance).to.be.bignumber.equal(balance);
+ expect(erc721Balance).to.be.bignumber.equal(ERC721_BALANCE);
+ expect(erc20Allowance).to.be.bignumber.equal(allowance);
+ expect(erc721Allowance).to.be.bignumber.equal(ERC721_ALLOWANCE);
+ });
+ });
+ describe('getTraderInfo', () => {
+ beforeEach(async () => {
+ signedOrder = await orderFactory.newSignedOrderAsync();
+ });
+ it('should return the correct info when no balances or allowances are set', async () => {
+ const traderInfo = await orderValidator.getTraderInfo.callAsync(signedOrder, takerAddress);
+ expect(traderInfo.makerBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ expect(traderInfo.makerAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ expect(traderInfo.takerBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ expect(traderInfo.takerAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ expect(traderInfo.makerZrxBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ expect(traderInfo.makerZrxAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ expect(traderInfo.takerZrxBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ expect(traderInfo.takerZrxAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ });
+ it('should return the correct info when balances and allowances are set', async () => {
+ const makerBalance = new BigNumber(123);
+ const makerAllowance = new BigNumber(456);
+ const makerZrxBalance = new BigNumber(789);
+ const takerZrxAllowance = new BigNumber(987);
+ await web3Wrapper.awaitTransactionSuccessAsync(
+ await erc20Token.setBalance.sendTransactionAsync(makerAddress, makerBalance),
+ constants.AWAIT_TRANSACTION_MINED_MS,
+ );
+ await web3Wrapper.awaitTransactionSuccessAsync(
+ await erc20Token.approve.sendTransactionAsync(erc20Proxy.address, makerAllowance, {
+ from: makerAddress,
+ }),
+ constants.AWAIT_TRANSACTION_MINED_MS,
+ );
+ await web3Wrapper.awaitTransactionSuccessAsync(
+ await zrxToken.setBalance.sendTransactionAsync(makerAddress, makerZrxBalance),
+ constants.AWAIT_TRANSACTION_MINED_MS,
+ );
+ await web3Wrapper.awaitTransactionSuccessAsync(
+ await zrxToken.approve.sendTransactionAsync(erc20Proxy.address, takerZrxAllowance, {
+ from: takerAddress,
+ }),
+ constants.AWAIT_TRANSACTION_MINED_MS,
+ );
+ await web3Wrapper.awaitTransactionSuccessAsync(
+ await erc721Token.mint.sendTransactionAsync(takerAddress, tokenId),
+ constants.AWAIT_TRANSACTION_MINED_MS,
+ );
+ await web3Wrapper.awaitTransactionSuccessAsync(
+ await erc721Token.approve.sendTransactionAsync(erc721Proxy.address, tokenId, {
+ from: takerAddress,
+ }),
+ constants.AWAIT_TRANSACTION_MINED_MS,
+ );
+ const traderInfo = await orderValidator.getTraderInfo.callAsync(signedOrder, takerAddress);
+ expect(traderInfo.makerBalance).to.be.bignumber.equal(makerBalance);
+ expect(traderInfo.makerAllowance).to.be.bignumber.equal(makerAllowance);
+ expect(traderInfo.takerBalance).to.be.bignumber.equal(ERC721_BALANCE);
+ expect(traderInfo.takerAllowance).to.be.bignumber.equal(ERC721_ALLOWANCE);
+ expect(traderInfo.makerZrxBalance).to.be.bignumber.equal(makerZrxBalance);
+ expect(traderInfo.makerZrxAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ expect(traderInfo.takerZrxBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ expect(traderInfo.takerZrxAllowance).to.be.bignumber.equal(takerZrxAllowance);
+ });
+ });
+ describe('getTradersInfo', () => {
+ beforeEach(async () => {
+ signedOrder = await orderFactory.newSignedOrderAsync();
+ signedOrder2 = await orderFactory.newSignedOrderAsync({
+ takerAssetData: assetDataUtils.encodeERC721AssetData(erc721Token.address, tokenId2),
+ });
+ });
+ it('should return the correct info when no balances or allowances have been set', async () => {
+ const orders = [signedOrder, signedOrder2];
+ const takers = [takerAddress, takerAddress];
+ const [traderInfo1, traderInfo2] = await orderValidator.getTradersInfo.callAsync(orders, takers);
+ expect(traderInfo1.makerBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ expect(traderInfo1.makerAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ expect(traderInfo1.takerBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ expect(traderInfo1.takerAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ expect(traderInfo1.makerZrxBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ expect(traderInfo1.makerZrxAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ expect(traderInfo1.takerZrxBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ expect(traderInfo1.takerZrxAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ expect(traderInfo2.makerBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ expect(traderInfo2.makerAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ expect(traderInfo2.takerBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ expect(traderInfo2.takerAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ expect(traderInfo2.makerZrxBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ expect(traderInfo2.makerZrxAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ expect(traderInfo2.takerZrxBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ expect(traderInfo2.takerZrxAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ });
+ it('should return the correct info when balances and allowances are set', async () => {
+ const makerBalance = new BigNumber(123);
+ const makerAllowance = new BigNumber(456);
+ const makerZrxBalance = new BigNumber(789);
+ const takerZrxAllowance = new BigNumber(987);
+ await web3Wrapper.awaitTransactionSuccessAsync(
+ await erc20Token.setBalance.sendTransactionAsync(makerAddress, makerBalance),
+ constants.AWAIT_TRANSACTION_MINED_MS,
+ );
+ await web3Wrapper.awaitTransactionSuccessAsync(
+ await erc20Token.approve.sendTransactionAsync(erc20Proxy.address, makerAllowance, {
+ from: makerAddress,
+ }),
+ constants.AWAIT_TRANSACTION_MINED_MS,
+ );
+ await web3Wrapper.awaitTransactionSuccessAsync(
+ await zrxToken.setBalance.sendTransactionAsync(makerAddress, makerZrxBalance),
+ constants.AWAIT_TRANSACTION_MINED_MS,
+ );
+ await web3Wrapper.awaitTransactionSuccessAsync(
+ await zrxToken.approve.sendTransactionAsync(erc20Proxy.address, takerZrxAllowance, {
+ from: takerAddress,
+ }),
+ constants.AWAIT_TRANSACTION_MINED_MS,
+ );
+ const isApproved = true;
+ await web3Wrapper.awaitTransactionSuccessAsync(
+ await erc721Token.setApprovalForAll.sendTransactionAsync(erc721Proxy.address, isApproved, {
+ from: takerAddress,
+ }),
+ constants.AWAIT_TRANSACTION_MINED_MS,
+ );
+ await web3Wrapper.awaitTransactionSuccessAsync(
+ await erc721Token.mint.sendTransactionAsync(takerAddress, tokenId2),
+ constants.AWAIT_TRANSACTION_MINED_MS,
+ );
+ const orders = [signedOrder, signedOrder2];
+ const takers = [takerAddress, takerAddress];
+ const [traderInfo1, traderInfo2] = await orderValidator.getTradersInfo.callAsync(orders, takers);
+
+ expect(traderInfo1.makerBalance).to.be.bignumber.equal(makerBalance);
+ expect(traderInfo1.makerAllowance).to.be.bignumber.equal(makerAllowance);
+ expect(traderInfo1.takerBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ expect(traderInfo1.takerAllowance).to.be.bignumber.equal(ERC721_ALLOWANCE);
+ expect(traderInfo1.makerZrxBalance).to.be.bignumber.equal(makerZrxBalance);
+ expect(traderInfo1.makerZrxAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ expect(traderInfo1.takerZrxBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ expect(traderInfo1.takerZrxAllowance).to.be.bignumber.equal(takerZrxAllowance);
+ expect(traderInfo2.makerBalance).to.be.bignumber.equal(makerBalance);
+ expect(traderInfo2.makerAllowance).to.be.bignumber.equal(makerAllowance);
+ expect(traderInfo2.takerBalance).to.be.bignumber.equal(ERC721_BALANCE);
+ expect(traderInfo2.takerAllowance).to.be.bignumber.equal(ERC721_ALLOWANCE);
+ expect(traderInfo2.makerZrxBalance).to.be.bignumber.equal(makerZrxBalance);
+ expect(traderInfo2.makerZrxAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ expect(traderInfo2.takerZrxBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ expect(traderInfo2.takerZrxAllowance).to.be.bignumber.equal(takerZrxAllowance);
+ });
+ });
+ describe('getOrderAndTraderInfo', () => {
+ beforeEach(async () => {
+ signedOrder = await orderFactory.newSignedOrderAsync();
+ });
+ it('should return the correct info when no balances or allowances are set', async () => {
+ const [orderInfo, traderInfo] = await orderValidator.getOrderAndTraderInfo.callAsync(
+ signedOrder,
+ takerAddress,
+ );
+ const expectedOrderHash = orderHashUtils.getOrderHashHex(signedOrder);
+ expect(orderInfo.orderStatus).to.be.equal(OrderStatus.FILLABLE);
+ expect(orderInfo.orderHash).to.be.equal(expectedOrderHash);
+ expect(orderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ expect(traderInfo.makerBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ expect(traderInfo.makerAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ expect(traderInfo.takerBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ expect(traderInfo.takerAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ expect(traderInfo.makerZrxBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ expect(traderInfo.makerZrxAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ expect(traderInfo.takerZrxBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ expect(traderInfo.takerZrxAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ });
+ it('should return the correct info when balances and allowances are set', async () => {
+ const makerBalance = new BigNumber(123);
+ const makerAllowance = new BigNumber(456);
+ const makerZrxBalance = new BigNumber(789);
+ const takerZrxAllowance = new BigNumber(987);
+ await web3Wrapper.awaitTransactionSuccessAsync(
+ await erc20Token.setBalance.sendTransactionAsync(makerAddress, makerBalance),
+ constants.AWAIT_TRANSACTION_MINED_MS,
+ );
+ await web3Wrapper.awaitTransactionSuccessAsync(
+ await erc20Token.approve.sendTransactionAsync(erc20Proxy.address, makerAllowance, {
+ from: makerAddress,
+ }),
+ constants.AWAIT_TRANSACTION_MINED_MS,
+ );
+ await web3Wrapper.awaitTransactionSuccessAsync(
+ await zrxToken.setBalance.sendTransactionAsync(makerAddress, makerZrxBalance),
+ constants.AWAIT_TRANSACTION_MINED_MS,
+ );
+ await web3Wrapper.awaitTransactionSuccessAsync(
+ await zrxToken.approve.sendTransactionAsync(erc20Proxy.address, takerZrxAllowance, {
+ from: takerAddress,
+ }),
+ constants.AWAIT_TRANSACTION_MINED_MS,
+ );
+ await web3Wrapper.awaitTransactionSuccessAsync(
+ await erc721Token.mint.sendTransactionAsync(takerAddress, tokenId),
+ constants.AWAIT_TRANSACTION_MINED_MS,
+ );
+ await web3Wrapper.awaitTransactionSuccessAsync(
+ await erc721Token.approve.sendTransactionAsync(erc721Proxy.address, tokenId, {
+ from: takerAddress,
+ }),
+ constants.AWAIT_TRANSACTION_MINED_MS,
+ );
+ const [orderInfo, traderInfo] = await orderValidator.getOrderAndTraderInfo.callAsync(
+ signedOrder,
+ takerAddress,
+ );
+ const expectedOrderHash = orderHashUtils.getOrderHashHex(signedOrder);
+ expect(orderInfo.orderStatus).to.be.equal(OrderStatus.FILLABLE);
+ expect(orderInfo.orderHash).to.be.equal(expectedOrderHash);
+ expect(orderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ expect(traderInfo.makerBalance).to.be.bignumber.equal(makerBalance);
+ expect(traderInfo.makerAllowance).to.be.bignumber.equal(makerAllowance);
+ expect(traderInfo.takerBalance).to.be.bignumber.equal(ERC721_BALANCE);
+ expect(traderInfo.takerAllowance).to.be.bignumber.equal(ERC721_ALLOWANCE);
+ expect(traderInfo.makerZrxBalance).to.be.bignumber.equal(makerZrxBalance);
+ expect(traderInfo.makerZrxAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ expect(traderInfo.takerZrxBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ expect(traderInfo.takerZrxAllowance).to.be.bignumber.equal(takerZrxAllowance);
+ });
+ });
+ describe('getOrdersAndTradersInfo', () => {
+ beforeEach(async () => {
+ signedOrder = await orderFactory.newSignedOrderAsync();
+ signedOrder2 = await orderFactory.newSignedOrderAsync({
+ takerAssetData: assetDataUtils.encodeERC721AssetData(erc721Token.address, tokenId2),
+ });
+ });
+ it('should return the correct info when no balances or allowances have been set', async () => {
+ const orders = [signedOrder, signedOrder2];
+ const takers = [takerAddress, takerAddress];
+ const [
+ [orderInfo1, orderInfo2],
+ [traderInfo1, traderInfo2],
+ ] = await orderValidator.getOrdersAndTradersInfo.callAsync(orders, takers);
+ const expectedOrderHash1 = orderHashUtils.getOrderHashHex(signedOrder);
+ const expectedOrderHash2 = orderHashUtils.getOrderHashHex(signedOrder2);
+ expect(orderInfo1.orderStatus).to.be.equal(OrderStatus.FILLABLE);
+ expect(orderInfo1.orderHash).to.be.equal(expectedOrderHash1);
+ expect(orderInfo1.orderTakerAssetFilledAmount).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ expect(orderInfo2.orderStatus).to.be.equal(OrderStatus.FILLABLE);
+ expect(orderInfo2.orderHash).to.be.equal(expectedOrderHash2);
+ expect(orderInfo2.orderTakerAssetFilledAmount).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ expect(traderInfo1.makerBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ expect(traderInfo1.makerAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ expect(traderInfo1.takerBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ expect(traderInfo1.takerAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ expect(traderInfo1.makerZrxBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ expect(traderInfo1.makerZrxAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ expect(traderInfo1.takerZrxBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ expect(traderInfo1.takerZrxAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ expect(traderInfo2.makerBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ expect(traderInfo2.makerAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ expect(traderInfo2.takerBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ expect(traderInfo2.takerAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ expect(traderInfo2.makerZrxBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ expect(traderInfo2.makerZrxAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ expect(traderInfo2.takerZrxBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ expect(traderInfo2.takerZrxAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ });
+ it('should return the correct info when balances and allowances are set', async () => {
+ const makerBalance = new BigNumber(123);
+ const makerAllowance = new BigNumber(456);
+ const makerZrxBalance = new BigNumber(789);
+ const takerZrxAllowance = new BigNumber(987);
+ await web3Wrapper.awaitTransactionSuccessAsync(
+ await erc20Token.setBalance.sendTransactionAsync(makerAddress, makerBalance),
+ constants.AWAIT_TRANSACTION_MINED_MS,
+ );
+ await web3Wrapper.awaitTransactionSuccessAsync(
+ await erc20Token.approve.sendTransactionAsync(erc20Proxy.address, makerAllowance, {
+ from: makerAddress,
+ }),
+ constants.AWAIT_TRANSACTION_MINED_MS,
+ );
+ await web3Wrapper.awaitTransactionSuccessAsync(
+ await zrxToken.setBalance.sendTransactionAsync(makerAddress, makerZrxBalance),
+ constants.AWAIT_TRANSACTION_MINED_MS,
+ );
+ await web3Wrapper.awaitTransactionSuccessAsync(
+ await zrxToken.approve.sendTransactionAsync(erc20Proxy.address, takerZrxAllowance, {
+ from: takerAddress,
+ }),
+ constants.AWAIT_TRANSACTION_MINED_MS,
+ );
+ const isApproved = true;
+ await web3Wrapper.awaitTransactionSuccessAsync(
+ await erc721Token.setApprovalForAll.sendTransactionAsync(erc721Proxy.address, isApproved, {
+ from: takerAddress,
+ }),
+ constants.AWAIT_TRANSACTION_MINED_MS,
+ );
+ await web3Wrapper.awaitTransactionSuccessAsync(
+ await erc721Token.mint.sendTransactionAsync(takerAddress, tokenId2),
+ constants.AWAIT_TRANSACTION_MINED_MS,
+ );
+ const orders = [signedOrder, signedOrder2];
+ const takers = [takerAddress, takerAddress];
+ const [
+ [orderInfo1, orderInfo2],
+ [traderInfo1, traderInfo2],
+ ] = await orderValidator.getOrdersAndTradersInfo.callAsync(orders, takers);
+ const expectedOrderHash1 = orderHashUtils.getOrderHashHex(signedOrder);
+ const expectedOrderHash2 = orderHashUtils.getOrderHashHex(signedOrder2);
+ expect(orderInfo1.orderStatus).to.be.equal(OrderStatus.FILLABLE);
+ expect(orderInfo1.orderHash).to.be.equal(expectedOrderHash1);
+ expect(orderInfo1.orderTakerAssetFilledAmount).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ expect(orderInfo2.orderStatus).to.be.equal(OrderStatus.FILLABLE);
+ expect(orderInfo2.orderHash).to.be.equal(expectedOrderHash2);
+ expect(orderInfo2.orderTakerAssetFilledAmount).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ expect(traderInfo1.makerBalance).to.be.bignumber.equal(makerBalance);
+ expect(traderInfo1.makerAllowance).to.be.bignumber.equal(makerAllowance);
+ expect(traderInfo1.takerBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ expect(traderInfo1.takerAllowance).to.be.bignumber.equal(ERC721_ALLOWANCE);
+ expect(traderInfo1.makerZrxBalance).to.be.bignumber.equal(makerZrxBalance);
+ expect(traderInfo1.makerZrxAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ expect(traderInfo1.takerZrxBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ expect(traderInfo1.takerZrxAllowance).to.be.bignumber.equal(takerZrxAllowance);
+ expect(traderInfo2.makerBalance).to.be.bignumber.equal(makerBalance);
+ expect(traderInfo2.makerAllowance).to.be.bignumber.equal(makerAllowance);
+ expect(traderInfo2.takerBalance).to.be.bignumber.equal(ERC721_BALANCE);
+ expect(traderInfo2.takerAllowance).to.be.bignumber.equal(ERC721_ALLOWANCE);
+ expect(traderInfo2.makerZrxBalance).to.be.bignumber.equal(makerZrxBalance);
+ expect(traderInfo2.makerZrxAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ expect(traderInfo2.takerZrxBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ expect(traderInfo2.takerZrxAllowance).to.be.bignumber.equal(takerZrxAllowance);
+ });
+ });
+});
+// tslint:disable:max-file-line-count
diff --git a/packages/contracts/test/utils/artifacts.ts b/packages/contracts/test/utils/artifacts.ts
index e86ad5406..21dd932c6 100644
--- a/packages/contracts/test/utils/artifacts.ts
+++ b/packages/contracts/test/utils/artifacts.ts
@@ -15,6 +15,7 @@ import * as InvalidERC721Receiver from '../../artifacts/InvalidERC721Receiver.js
import * as MixinAuthorizable from '../../artifacts/MixinAuthorizable.json';
import * as MultiSigWallet from '../../artifacts/MultiSigWallet.json';
import * as MultiSigWalletWithTimeLock from '../../artifacts/MultiSigWalletWithTimeLock.json';
+import * as OrderValidator from '../../artifacts/OrderValidator.json';
import * as TestAssetProxyDispatcher from '../../artifacts/TestAssetProxyDispatcher.json';
import * as TestAssetProxyOwner from '../../artifacts/TestAssetProxyOwner.json';
import * as TestConstants from '../../artifacts/TestConstants.json';
@@ -46,6 +47,7 @@ export const artifacts = {
MixinAuthorizable: (MixinAuthorizable as any) as ContractArtifact,
MultiSigWallet: (MultiSigWallet as any) as ContractArtifact,
MultiSigWalletWithTimeLock: (MultiSigWalletWithTimeLock as any) as ContractArtifact,
+ OrderValidator: (OrderValidator as any) as ContractArtifact,
TestAssetProxyOwner: (TestAssetProxyOwner as any) as ContractArtifact,
TestAssetProxyDispatcher: (TestAssetProxyDispatcher as any) as ContractArtifact,
TestConstants: (TestConstants as any) as ContractArtifact,