aboutsummaryrefslogtreecommitdiffstats
path: root/contracts/extensions
diff options
context:
space:
mode:
Diffstat (limited to 'contracts/extensions')
-rw-r--r--contracts/extensions/CHANGELOG.json74
-rw-r--r--contracts/extensions/CHANGELOG.md32
-rw-r--r--contracts/extensions/DEPLOYS.json31
-rw-r--r--contracts/extensions/README.md69
-rw-r--r--contracts/extensions/compiler.json22
-rw-r--r--contracts/extensions/contracts/BalanceThresholdFilter/BalanceThresholdFilter.sol45
-rw-r--r--contracts/extensions/contracts/BalanceThresholdFilter/MixinBalanceThresholdFilterCore.sol135
-rw-r--r--contracts/extensions/contracts/BalanceThresholdFilter/MixinExchangeCalldata.sol103
-rw-r--r--contracts/extensions/contracts/BalanceThresholdFilter/interfaces/IBalanceThresholdFilterCore.sol55
-rw-r--r--contracts/extensions/contracts/BalanceThresholdFilter/interfaces/IThresholdAsset.sol31
-rw-r--r--contracts/extensions/contracts/BalanceThresholdFilter/mixins/MBalanceThresholdFilterCore.sol54
-rw-r--r--contracts/extensions/contracts/BalanceThresholdFilter/mixins/MExchangeCalldata.sol56
-rw-r--r--contracts/extensions/contracts/DutchAuction/DutchAuction.sol205
-rw-r--r--contracts/extensions/contracts/Forwarder/Forwarder.sol50
-rw-r--r--contracts/extensions/contracts/Forwarder/MixinAssets.sol143
-rw-r--r--contracts/extensions/contracts/Forwarder/MixinExchangeWrapper.sol260
-rw-r--r--contracts/extensions/contracts/Forwarder/MixinForwarderCore.sol214
-rw-r--r--contracts/extensions/contracts/Forwarder/MixinWeth.sol113
-rw-r--r--contracts/extensions/contracts/Forwarder/interfaces/IAssets.sol34
-rw-r--r--contracts/extensions/contracts/Forwarder/interfaces/IForwarder.sol30
-rw-r--r--contracts/extensions/contracts/Forwarder/interfaces/IForwarderCore.sol80
-rw-r--r--contracts/extensions/contracts/Forwarder/libs/LibConstants.sol62
-rw-r--r--contracts/extensions/contracts/Forwarder/libs/LibForwarderErrors.sol34
-rw-r--r--contracts/extensions/contracts/Forwarder/mixins/MAssets.sol53
-rw-r--r--contracts/extensions/contracts/Forwarder/mixins/MExchangeWrapper.sol87
-rw-r--r--contracts/extensions/contracts/Forwarder/mixins/MWeth.sol41
-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.sol218
-rw-r--r--contracts/extensions/package.json93
-rw-r--r--contracts/extensions/src/artifacts/index.ts15
-rw-r--r--contracts/extensions/src/index.ts2
-rw-r--r--contracts/extensions/src/wrappers/index.ts5
-rw-r--r--contracts/extensions/test/extensions/balance_threshold_filter.ts1644
-rw-r--r--contracts/extensions/test/extensions/dutch_auction.ts378
-rw-r--r--contracts/extensions/test/extensions/forwarder.ts1291
-rw-r--r--contracts/extensions/test/extensions/order_matcher.ts818
-rw-r--r--contracts/extensions/test/extensions/order_validator.ts609
-rw-r--r--contracts/extensions/test/global_hooks.ts17
-rw-r--r--contracts/extensions/test/utils/balance_threshold_wrapper.ts283
-rw-r--r--contracts/extensions/test/utils/dutch_auction_test_wrapper.ts62
-rw-r--r--contracts/extensions/test/utils/forwarder_wrapper.ts124
-rw-r--r--contracts/extensions/tsconfig.json17
-rw-r--r--contracts/extensions/tslint.json6
50 files changed, 0 insertions, 8258 deletions
diff --git a/contracts/extensions/CHANGELOG.json b/contracts/extensions/CHANGELOG.json
deleted file mode 100644
index 920fef05a..000000000
--- a/contracts/extensions/CHANGELOG.json
+++ /dev/null
@@ -1,74 +0,0 @@
-[
- {
- "version": "2.0.0",
- "changes": [
- {
- "note": "Upgrade the bignumber.js to v8.0.2",
- "pr": 1517
- }
- ]
- },
- {
- "timestamp": 1547747677,
- "version": "1.2.3",
- "changes": [
- {
- "note": "Dependencies updated"
- }
- ]
- },
- {
- "timestamp": 1547561734,
- "version": "1.2.2",
- "changes": [
- {
- "note": "Dependencies updated"
- }
- ]
- },
- {
- "timestamp": 1547225310,
- "version": "1.2.1",
- "changes": [
- {
- "note": "Dependencies updated"
- }
- ]
- },
- {
- "version": "1.2.0",
- "changes": [
- {
- "note": "Added Dutch Auction Wrapper",
- "pr": 1465
- }
- ],
- "timestamp": 1547040760
- },
- {
- "version": "1.1.0",
- "changes": [
- {
- "note": "Added Balance Threshold Filter",
- "pr": 1383
- },
- {
- "note": "Add OrderMatcher",
- "pr": 1117
- },
- {
- "note": "Add OrderValidator",
- "pr": 1464
- }
- ]
- },
- {
- "timestamp": 1544741676,
- "version": "1.0.2",
- "changes": [
- {
- "note": "Dependencies updated"
- }
- ]
- }
-]
diff --git a/contracts/extensions/CHANGELOG.md b/contracts/extensions/CHANGELOG.md
deleted file mode 100644
index 94ffdfb67..000000000
--- a/contracts/extensions/CHANGELOG.md
+++ /dev/null
@@ -1,32 +0,0 @@
-<!--
-changelogUtils.file is auto-generated using the monorepo-scripts package. Don't edit directly.
-Edit the package's CHANGELOG.json file only.
--->
-
-CHANGELOG
-
-## v1.2.3 - _January 17, 2019_
-
- * Dependencies updated
-
-## v1.2.2 - _January 15, 2019_
-
- * Dependencies updated
-
-## v1.2.1 - _January 11, 2019_
-
- * Dependencies updated
-
-## v1.2.0 - _January 9, 2019_
-
- * Added Dutch Auction Wrapper (#1465)
-
-## v1.1.0 - _Invalid date_
-
- * Added Balance Threshold Filter (#1383)
- * Add OrderMatcher (#1117)
- * Add OrderValidator (#1464)
-
-## v1.0.2 - _December 13, 2018_
-
- * Dependencies updated
diff --git a/contracts/extensions/DEPLOYS.json b/contracts/extensions/DEPLOYS.json
deleted file mode 100644
index 1a093bf77..000000000
--- a/contracts/extensions/DEPLOYS.json
+++ /dev/null
@@ -1,31 +0,0 @@
-[
- {
- "name": "Forwarder",
- "version": "1.1.0",
- "changes": [
- {
- "note": "Round up when calculating remaining amounts in marketBuy functions",
- "pr": 1162,
- "networks": {
- "1": "0x5468a1dc173652ee28d249c271fa9933144746b1",
- "3": "0x2240dab907db71e64d3e0dba4800c83b5c502d4e",
- "42": "0x17992e4ffb22730138e4b62aaa6367fa9d3699a6"
- }
- }
- ]
- },
- {
- "name": "Forwarder",
- "version": "1.0.0",
- "changes": [
- {
- "note": "protocol v2 deploy",
- "networks": {
- "1": "0x7afc2d5107af94c462a194d2c21b5bdd238709d6",
- "3": "0x3983e204b12b3c02fb0638caf2cd406a62e0ead3",
- "42": "0xd85e2fa7e7e252b27b01bf0d65c946959d2f45b8"
- }
- }
- ]
- }
-]
diff --git a/contracts/extensions/README.md b/contracts/extensions/README.md
deleted file mode 100644
index 820f6e78a..000000000
--- a/contracts/extensions/README.md
+++ /dev/null
@@ -1,69 +0,0 @@
-## Contract extensions
-
-Smart contracts that implement extensions for the 0x protocol.
-
-## Usage
-
-Contract extensions of the protocol can be found in the [contracts](./contracts) directory. This directory contains contracts that interact with the 2.0.0 contracts and will be used in production, such as the [Forwarder](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/forwarder-specification.md) contract.
-
-## Bug bounty
-
-A bug bounty for the 2.0.0 contracts is ongoing! Instructions can be found [here](https://0xproject.com/wiki#Bug-Bounty).
-
-## Contributing
-
-We strongly recommend that the community help us make improvements and determine the future direction of the protocol. To report bugs within this package, please create an issue in this repository.
-
-For proposals regarding the 0x protocol's smart contract architecture, message format, or additional functionality, go to the [0x Improvement Proposals (ZEIPs)](https://github.com/0xProject/ZEIPs) repository and follow the contribution guidelines provided therein.
-
-Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started.
-
-### Install Dependencies
-
-If you don't have yarn workspaces enabled (Yarn < v1.0) - enable them:
-
-```bash
-yarn config set workspaces-experimental true
-```
-
-Then install dependencies
-
-```bash
-yarn install
-```
-
-### Build
-
-To build this package and all other monorepo packages that it depends on, run the following from the monorepo root directory:
-
-```bash
-PKG=@0x/contracts-extensions yarn build
-```
-
-Or continuously rebuild on change:
-
-```bash
-PKG=@0x/contracts-extensions yarn watch
-```
-
-### Clean
-
-```bash
-yarn clean
-```
-
-### Lint
-
-```bash
-yarn lint
-```
-
-### Run Tests
-
-```bash
-yarn test
-```
-
-#### Testing options
-
-Contracts testing options like coverage, profiling, revert traces or backing node choosing - are described [here](../TESTING.md).
diff --git a/contracts/extensions/compiler.json b/contracts/extensions/compiler.json
deleted file mode 100644
index 2bb468724..000000000
--- a/contracts/extensions/compiler.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "artifactsDir": "./generated-artifacts",
- "contractsDir": "./contracts",
- "compilerSettings": {
- "optimizer": {
- "enabled": true,
- "runs": 1000000
- },
- "outputSelection": {
- "*": {
- "*": [
- "abi",
- "evm.bytecode.object",
- "evm.bytecode.sourceMap",
- "evm.deployedBytecode.object",
- "evm.deployedBytecode.sourceMap"
- ]
- }
- }
- },
- "contracts": ["BalanceThresholdFilter", "DutchAuction", "Forwarder", "OrderMatcher", "OrderValidator"]
-}
diff --git a/contracts/extensions/contracts/BalanceThresholdFilter/BalanceThresholdFilter.sol b/contracts/extensions/contracts/BalanceThresholdFilter/BalanceThresholdFilter.sol
deleted file mode 100644
index 16cacd461..000000000
--- a/contracts/extensions/contracts/BalanceThresholdFilter/BalanceThresholdFilter.sol
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
-
- 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";
-import "./interfaces/IThresholdAsset.sol";
-import "./MixinBalanceThresholdFilterCore.sol";
-
-
-contract BalanceThresholdFilter is
- MixinBalanceThresholdFilterCore
-{
-
- /// @dev Constructs BalanceThresholdFilter.
- /// @param exchange Address of 0x exchange.
- /// @param thresholdAsset The asset that must be held by makers/takers.
- /// @param balanceThreshold The minimum balance of `thresholdAsset` that must be held by makers/takers.
- constructor(
- address exchange,
- address thresholdAsset,
- uint256 balanceThreshold
- )
- public
- {
- EXCHANGE = IExchange(exchange);
- THRESHOLD_ASSET = IThresholdAsset(thresholdAsset);
- BALANCE_THRESHOLD = balanceThreshold;
- }
-}
diff --git a/contracts/extensions/contracts/BalanceThresholdFilter/MixinBalanceThresholdFilterCore.sol b/contracts/extensions/contracts/BalanceThresholdFilter/MixinBalanceThresholdFilterCore.sol
deleted file mode 100644
index da050bf72..000000000
--- a/contracts/extensions/contracts/BalanceThresholdFilter/MixinBalanceThresholdFilterCore.sol
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
-
- 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/LICENSE2.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-libs/contracts/libs/LibExchangeSelectors.sol";
-import "@0x/contracts-libs/contracts/libs/LibOrder.sol";
-import "./mixins/MBalanceThresholdFilterCore.sol";
-import "./MixinExchangeCalldata.sol";
-
-
-contract MixinBalanceThresholdFilterCore is
- MBalanceThresholdFilterCore,
- MixinExchangeCalldata,
- LibOrder,
- LibExchangeSelectors
-{
-
- /// @dev Executes an Exchange transaction iff the maker and taker meet
- /// the hold at least `BALANCE_THRESHOLD` of the asset `THRESHOLD_ASSET` OR
- /// the exchange function is a cancellation.
- /// Supported Exchange functions:
- /// batchFillOrders
- /// batchFillOrdersNoThrow
- /// batchFillOrKillOrders
- /// fillOrder
- /// fillOrderNoThrow
- /// fillOrKillOrder
- /// marketBuyOrders
- /// marketBuyOrdersNoThrow
- /// marketSellOrders
- /// marketSellOrdersNoThrow
- /// matchOrders
- /// cancelOrder
- /// batchCancelOrders
- /// cancelOrdersUpTo
- /// Trying to call any other exchange function will throw.
- /// @param salt Arbitrary number to ensure uniqueness of transaction hash.
- /// @param signerAddress Address of transaction signer.
- /// @param signedExchangeTransaction AbiV2 encoded calldata.
- /// @param signature Proof of signer transaction by signer.
- function executeTransaction(
- uint256 salt,
- address signerAddress,
- bytes signedExchangeTransaction,
- bytes signature
- )
- external
- {
- // Get accounts whose balances must be validated
- address[] memory addressesToValidate = getAddressesToValidate(signerAddress);
-
- // Validate account balances
- uint256 balanceThreshold = BALANCE_THRESHOLD;
- IThresholdAsset thresholdAsset = THRESHOLD_ASSET;
- for (uint256 i = 0; i < addressesToValidate.length; ++i) {
- uint256 addressBalance = thresholdAsset.balanceOf(addressesToValidate[i]);
- require(
- addressBalance >= balanceThreshold,
- "AT_LEAST_ONE_ADDRESS_DOES_NOT_MEET_BALANCE_THRESHOLD"
- );
- }
- emit ValidatedAddresses(addressesToValidate);
-
- // All addresses are valid. Execute exchange function.
- EXCHANGE.executeTransaction(
- salt,
- signerAddress,
- signedExchangeTransaction,
- signature
- );
- }
-
- /// @dev Constructs an array of addresses to be validated.
- /// Addresses depend on which Exchange function is to be called
- /// (defined by `signedExchangeTransaction` above).
- /// @param signerAddress Address of transaction signer.
- /// @return addressesToValidate Array of addresses to validate.
- function getAddressesToValidate(address signerAddress)
- internal pure
- returns (address[] memory addressesToValidate)
- {
- bytes4 exchangeFunctionSelector = bytes4(exchangeCalldataload(0));
- // solhint-disable expression-indent
- if (
- exchangeFunctionSelector == BATCH_FILL_ORDERS_SELECTOR ||
- exchangeFunctionSelector == BATCH_FILL_ORDERS_NO_THROW_SELECTOR ||
- exchangeFunctionSelector == BATCH_FILL_OR_KILL_ORDERS_SELECTOR ||
- exchangeFunctionSelector == MARKET_BUY_ORDERS_SELECTOR ||
- exchangeFunctionSelector == MARKET_BUY_ORDERS_NO_THROW_SELECTOR ||
- exchangeFunctionSelector == MARKET_SELL_ORDERS_SELECTOR ||
- exchangeFunctionSelector == MARKET_SELL_ORDERS_NO_THROW_SELECTOR
- ) {
- addressesToValidate = loadMakerAddressesFromOrderArray(0);
- addressesToValidate = addressesToValidate.append(signerAddress);
- } else if (
- exchangeFunctionSelector == FILL_ORDER_SELECTOR ||
- exchangeFunctionSelector == FILL_ORDER_NO_THROW_SELECTOR ||
- exchangeFunctionSelector == FILL_OR_KILL_ORDER_SELECTOR
- ) {
- address makerAddress = loadMakerAddressFromOrder(0);
- addressesToValidate = addressesToValidate.append(makerAddress);
- addressesToValidate = addressesToValidate.append(signerAddress);
- } else if (exchangeFunctionSelector == MATCH_ORDERS_SELECTOR) {
- address leftMakerAddress = loadMakerAddressFromOrder(0);
- addressesToValidate = addressesToValidate.append(leftMakerAddress);
- address rightMakerAddress = loadMakerAddressFromOrder(1);
- addressesToValidate = addressesToValidate.append(rightMakerAddress);
- addressesToValidate = addressesToValidate.append(signerAddress);
- } else if (
- exchangeFunctionSelector != CANCEL_ORDER_SELECTOR &&
- exchangeFunctionSelector != BATCH_CANCEL_ORDERS_SELECTOR &&
- exchangeFunctionSelector != CANCEL_ORDERS_UP_TO_SELECTOR
- ) {
- revert("INVALID_OR_BLOCKED_EXCHANGE_SELECTOR");
- }
- // solhint-enable expression-indent
- return addressesToValidate;
- }
-}
diff --git a/contracts/extensions/contracts/BalanceThresholdFilter/MixinExchangeCalldata.sol b/contracts/extensions/contracts/BalanceThresholdFilter/MixinExchangeCalldata.sol
deleted file mode 100644
index a15e95a9d..000000000
--- a/contracts/extensions/contracts/BalanceThresholdFilter/MixinExchangeCalldata.sol
+++ /dev/null
@@ -1,103 +0,0 @@
-
- /*
-
- 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/LICENSE2.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 "./mixins/MExchangeCalldata.sol";
-import "@0x/contracts-libs/contracts/libs/LibAddressArray.sol";
-
-
-contract MixinExchangeCalldata is
- MExchangeCalldata
-{
-
- using LibAddressArray for address[];
-
- /// @dev Emulates the `calldataload` opcode on the embedded Exchange calldata,
- /// which is accessed through `signedExchangeTransaction`.
- /// @param offset Offset into the Exchange calldata.
- /// @return value Corresponding 32 byte value stored at `offset`.
- function exchangeCalldataload(uint256 offset)
- internal pure
- returns (bytes32 value)
- {
- assembly {
- // Pointer to exchange transaction
- // 0x04 for calldata selector
- // 0x40 to access `signedExchangeTransaction`, which is the third parameter
- let exchangeTxPtr := calldataload(0x44)
-
- // Offset into Exchange calldata
- // We compute this by adding 0x24 to the `exchangeTxPtr` computed above.
- // 0x04 for calldata selector
- // 0x20 for length field of `signedExchangeTransaction`
- let exchangeCalldataOffset := add(exchangeTxPtr, add(0x24, offset))
- value := calldataload(exchangeCalldataOffset)
- }
- return value;
- }
-
- /// @dev Convenience function that skips the 4 byte selector when loading
- /// from the embedded Exchange calldata.
- /// @param offset Offset into the Exchange calldata (minus the 4 byte selector)
- /// @return value Corresponding 32 byte value stored at `offset` + 4.
- function loadExchangeData(uint256 offset)
- internal pure
- returns (bytes32 value)
- {
- value = exchangeCalldataload(offset + 4);
- return value;
- }
-
- /// @dev Extracts the maker address from an order stored in the Exchange calldata
- /// (which is embedded in `signedExchangeTransaction`).
- /// @param orderParamIndex Index of the order in the Exchange function's signature.
- /// @return makerAddress The extracted maker address.
- function loadMakerAddressFromOrder(uint256 orderParamIndex)
- internal pure
- returns (address makerAddress)
- {
- uint256 orderOffsetInBytes = orderParamIndex * 32;
- uint256 orderPtr = uint256(loadExchangeData(orderOffsetInBytes));
- makerAddress = address(loadExchangeData(orderPtr));
- return makerAddress;
- }
-
- /// @dev Extracts the maker addresses from an array of orders stored in the Exchange calldata
- /// (which is embedded in `signedExchangeTransaction`).
- /// @param orderArrayParamIndex Index of the order array in the Exchange function's signature
- /// @return makerAddresses The extracted maker addresses.
- function loadMakerAddressesFromOrderArray(uint256 orderArrayParamIndex)
- internal pure
- returns (address[] makerAddresses)
- {
- uint256 orderArrayOffsetInBytes = orderArrayParamIndex * 32;
- uint256 orderArrayPtr = uint256(loadExchangeData(orderArrayOffsetInBytes));
- uint256 orderArrayLength = uint256(loadExchangeData(orderArrayPtr));
- uint256 orderArrayLengthInBytes = orderArrayLength * 32;
- uint256 orderArrayElementPtr = orderArrayPtr + 32;
- uint256 orderArrayElementEndPtr = orderArrayElementPtr + orderArrayLengthInBytes;
- for (uint orderPtrOffset = orderArrayElementPtr; orderPtrOffset < orderArrayElementEndPtr; orderPtrOffset += 32) {
- uint256 orderPtr = uint256(loadExchangeData(orderPtrOffset));
- address makerAddress = address(loadExchangeData(orderPtr + orderArrayElementPtr));
- makerAddresses = makerAddresses.append(makerAddress);
- }
- return makerAddresses;
- }
-}
diff --git a/contracts/extensions/contracts/BalanceThresholdFilter/interfaces/IBalanceThresholdFilterCore.sol b/contracts/extensions/contracts/BalanceThresholdFilter/interfaces/IBalanceThresholdFilterCore.sol
deleted file mode 100644
index 4a1bf1fb2..000000000
--- a/contracts/extensions/contracts/BalanceThresholdFilter/interfaces/IBalanceThresholdFilterCore.sol
+++ /dev/null
@@ -1,55 +0,0 @@
-
-/*
-
- 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 IBalanceThresholdFilterCore {
-
- /// @dev Executes an Exchange transaction iff the maker and taker meet
- /// the hold at least `BALANCE_THRESHOLD` of the asset `THRESHOLD_ASSET` OR
- /// the exchange function is a cancellation.
- /// Supported Exchange functions:
- /// - batchFillOrders
- /// - batchFillOrdersNoThrow
- /// - batchFillOrKillOrders
- /// - fillOrder
- /// - fillOrderNoThrow
- /// - fillOrKillOrder
- /// - marketBuyOrders
- /// - marketBuyOrdersNoThrow
- /// - marketSellOrders
- /// - marketSellOrdersNoThrow
- /// - matchOrders
- /// - cancelOrder
- /// - batchCancelOrders
- /// - cancelOrdersUpTo
- /// Trying to call any other exchange function will throw.
- /// @param salt Arbitrary number to ensure uniqueness of transaction hash.
- /// @param signerAddress Address of transaction signer.
- /// @param signedExchangeTransaction AbiV2 encoded calldata.
- /// @param signature Proof of signer transaction by signer.
- function executeTransaction(
- uint256 salt,
- address signerAddress,
- bytes signedExchangeTransaction,
- bytes signature
- )
- external;
-}
diff --git a/contracts/extensions/contracts/BalanceThresholdFilter/interfaces/IThresholdAsset.sol b/contracts/extensions/contracts/BalanceThresholdFilter/interfaces/IThresholdAsset.sol
deleted file mode 100644
index f78f9c2de..000000000
--- a/contracts/extensions/contracts/BalanceThresholdFilter/interfaces/IThresholdAsset.sol
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
-
- 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 IThresholdAsset {
-
- /// @param _owner The address from which the balance will be retrieved
- /// @return Balance of owner
- function balanceOf(address _owner)
- external
- view
- returns (uint256);
-
-}
diff --git a/contracts/extensions/contracts/BalanceThresholdFilter/mixins/MBalanceThresholdFilterCore.sol b/contracts/extensions/contracts/BalanceThresholdFilter/mixins/MBalanceThresholdFilterCore.sol
deleted file mode 100644
index 074686e8d..000000000
--- a/contracts/extensions/contracts/BalanceThresholdFilter/mixins/MBalanceThresholdFilterCore.sol
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
-
- 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";
-import "../interfaces/IThresholdAsset.sol";
-import "../interfaces/IBalanceThresholdFilterCore.sol";
-
-
-contract MBalanceThresholdFilterCore is
- IBalanceThresholdFilterCore
-{
-
- // Points to 0x exchange contract
- // solhint-disable var-name-mixedcase
- IExchange internal EXCHANGE;
-
- // The asset that must be held by makers/takers
- IThresholdAsset internal THRESHOLD_ASSET;
-
- // The minimum balance of `THRESHOLD_ASSET` that must be held by makers/takers
- uint256 internal BALANCE_THRESHOLD;
- // solhint-enable var-name-mixedcase
-
- // Addresses that hold at least `BALANCE_THRESHOLD` of `THRESHOLD_ASSET`
- event ValidatedAddresses (
- address[] addresses
- );
-
- /// @dev Constructs an array of addresses to be validated.
- /// Addresses depend on which Exchange function is to be called
- /// (defined by `signedExchangeTransaction` above).
- /// @param signerAddress Address of transaction signer.
- /// @return addressesToValidate Array of addresses to validate.
- function getAddressesToValidate(address signerAddress)
- internal pure
- returns (address[] memory addressesToValidate);
-}
diff --git a/contracts/extensions/contracts/BalanceThresholdFilter/mixins/MExchangeCalldata.sol b/contracts/extensions/contracts/BalanceThresholdFilter/mixins/MExchangeCalldata.sol
deleted file mode 100644
index 40536d820..000000000
--- a/contracts/extensions/contracts/BalanceThresholdFilter/mixins/MExchangeCalldata.sol
+++ /dev/null
@@ -1,56 +0,0 @@
-
- /*
-
- 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/LICENSE2.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 MExchangeCalldata {
-
- /// @dev Emulates the `calldataload` opcode on the embedded Exchange calldata,
- /// which is accessed through `signedExchangeTransaction`.
- /// @param offset Offset into the Exchange calldata.
- /// @return value Corresponding 32 byte value stored at `offset`.
- function exchangeCalldataload(uint256 offset)
- internal pure
- returns (bytes32 value);
-
- /// @dev Convenience function that skips the 4 byte selector when loading
- /// from the embedded Exchange calldata.
- /// @param offset Offset into the Exchange calldata (minus the 4 byte selector)
- /// @return value Corresponding 32 byte value stored at `offset` + 4.
- function loadExchangeData(uint256 offset)
- internal pure
- returns (bytes32 value);
-
- /// @dev Extracts the maker address from an order stored in the Exchange calldata
- /// (which is embedded in `signedExchangeTransaction`).
- /// @param orderParamIndex Index of the order in the Exchange function's signature.
- /// @return makerAddress The extracted maker address.
- function loadMakerAddressFromOrder(uint256 orderParamIndex)
- internal pure
- returns (address makerAddress);
-
- /// @dev Extracts the maker addresses from an array of orders stored in the Exchange calldata
- /// (which is embedded in `signedExchangeTransaction`).
- /// @param orderArrayParamIndex Index of the order array in the Exchange function's signature
- /// @return makerAddresses The extracted maker addresses.
- function loadMakerAddressesFromOrderArray(uint256 orderArrayParamIndex)
- internal pure
- returns (address[] makerAddresses);
-}
diff --git a/contracts/extensions/contracts/DutchAuction/DutchAuction.sol b/contracts/extensions/contracts/DutchAuction/DutchAuction.sol
deleted file mode 100644
index 9c9f3990a..000000000
--- a/contracts/extensions/contracts/DutchAuction/DutchAuction.sol
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
-
- 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-interfaces/contracts/protocol/Exchange/IExchange.sol";
-import "@0x/contracts-libs/contracts/libs/LibOrder.sol";
-import "@0x/contracts-tokens/contracts/tokens/ERC20Token/IERC20Token.sol";
-import "@0x/contracts-utils/contracts/utils/LibBytes/LibBytes.sol";
-import "@0x/contracts-utils/contracts/utils/SafeMath/SafeMath.sol";
-
-
-contract DutchAuction is
- SafeMath
-{
- using LibBytes for bytes;
-
- // solhint-disable var-name-mixedcase
- IExchange internal EXCHANGE;
-
- struct AuctionDetails {
- uint256 beginTimeSeconds; // Auction begin unix timestamp: sellOrder.makerAssetData
- uint256 endTimeSeconds; // Auction end unix timestamp: sellOrder.expiryTimeSeconds
- uint256 beginAmount; // Auction begin amount: sellOrder.makerAssetData
- uint256 endAmount; // Auction end amount: sellOrder.takerAssetAmount
- uint256 currentAmount; // Calculated amount given block.timestamp
- uint256 currentTimeSeconds; // block.timestamp
- }
-
- constructor (address _exchange)
- public
- {
- EXCHANGE = IExchange(_exchange);
- }
-
- /// @dev 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.
- /// sellOrder.expiryTimeSeconds is the end time of the auction.
- /// sellOrder.takerAssetAmount is the end amount of the auction (lowest possible amount).
- /// sellOrder.makerAssetData is the ABI encoded Asset Proxy data with the following data appended
- /// buyOrder.makerAssetData is the buyers bid on the auction, must meet the amount for the current block timestamp
- /// (uint256 beginTimeSeconds, uint256 beginAmount).
- /// This function reverts in the following scenarios:
- /// * Auction has not started (auctionDetails.currentTimeSeconds < auctionDetails.beginTimeSeconds)
- /// * Auction has expired (auctionDetails.endTimeSeconds < auctionDetails.currentTimeSeconds)
- /// * Amount is invalid: Buy order amount is too low (buyOrder.makerAssetAmount < auctionDetails.currentAmount)
- /// * Amount is invalid: Invalid begin amount (auctionDetails.beginAmount > auctionDetails.endAmount)
- /// * Any failure in the 0x Match Orders
- /// @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 buySignature Proof that order was created by the buyer.
- /// @param sellSignature Proof that order was created by the seller.
- /// @return matchedFillResults amounts filled and fees paid by maker and taker of matched orders.
- function matchOrders(
- LibOrder.Order memory buyOrder,
- LibOrder.Order memory sellOrder,
- bytes memory buySignature,
- bytes memory sellSignature
- )
- public
- returns (LibFillResults.MatchedFillResults memory matchedFillResults)
- {
- AuctionDetails memory auctionDetails = getAuctionDetails(sellOrder);
- // Ensure the auction has not yet started
- require(
- auctionDetails.currentTimeSeconds >= auctionDetails.beginTimeSeconds,
- "AUCTION_NOT_STARTED"
- );
- // Ensure the auction has not expired. This will fail later in 0x but we can save gas by failing early
- require(
- sellOrder.expirationTimeSeconds > auctionDetails.currentTimeSeconds,
- "AUCTION_EXPIRED"
- );
- // Validate the buyer amount is greater than the current auction amount
- require(
- buyOrder.makerAssetAmount >= auctionDetails.currentAmount,
- "INVALID_AMOUNT"
- );
- // Match orders, maximally filling `buyOrder`
- matchedFillResults = EXCHANGE.matchOrders(
- buyOrder,
- sellOrder,
- buySignature,
- sellSignature
- );
- // The difference in sellOrder.takerAssetAmount and current amount is given as spread to the matcher
- // This may include additional spread from the buyOrder.makerAssetAmount and the currentAmount.
- // e.g currentAmount is 30, sellOrder.takerAssetAmount is 10 and buyOrder.makerAssetamount is 40.
- // 10 (40-30) is returned to the buyer, 20 (30-10) sent to the seller and 10 has previously
- // been transferred to the seller during matchOrders
- uint256 leftMakerAssetSpreadAmount = matchedFillResults.leftMakerAssetSpreadAmount;
- if (leftMakerAssetSpreadAmount > 0) {
- // ERC20 Asset data itself is encoded as follows:
- //
- // | Area | Offset | Length | Contents |
- // |----------|--------|---------|-------------------------------------|
- // | Header | 0 | 4 | function selector |
- // | Params | | 1 * 32 | function parameters: |
- // | | 4 | 12 | 1. token address padding |
- // | | 16 | 20 | 2. token address |
- bytes memory assetData = sellOrder.takerAssetData;
- address token = assetData.readAddress(16);
- // Calculate the excess from the buy order. This can occur if the buyer sends in a higher
- // amount than the calculated current amount
- uint256 buyerExcessAmount = safeSub(buyOrder.makerAssetAmount, auctionDetails.currentAmount);
- uint256 sellerExcessAmount = safeSub(leftMakerAssetSpreadAmount, buyerExcessAmount);
- // Return the difference between auctionDetails.currentAmount and sellOrder.takerAssetAmount
- // to the seller
- if (sellerExcessAmount > 0) {
- IERC20Token(token).transfer(sellOrder.makerAddress, sellerExcessAmount);
- }
- // Return the difference between buyOrder.makerAssetAmount and auctionDetails.currentAmount
- // to the buyer
- if (buyerExcessAmount > 0) {
- IERC20Token(token).transfer(buyOrder.makerAddress, buyerExcessAmount);
- }
- }
- return matchedFillResults;
- }
-
- /// @dev Calculates the Auction Details for the given order
- /// @param order The sell order
- /// @return AuctionDetails
- function getAuctionDetails(
- LibOrder.Order memory order
- )
- public
- returns (AuctionDetails memory auctionDetails)
- {
- uint256 makerAssetDataLength = order.makerAssetData.length;
- // It is unknown the encoded data of makerAssetData, we assume the last 64 bytes
- // are the Auction Details encoding.
- // Auction Details is encoded as follows:
- //
- // | Area | Offset | Length | Contents |
- // |----------|--------|---------|-------------------------------------|
- // | Params | | 2 * 32 | parameters: |
- // | | -64 | 32 | 1. auction begin unix timestamp |
- // | | -32 | 32 | 2. auction begin begin amount |
- // ERC20 asset data length is 4+32, 64 for auction details results in min length 100
- require(
- makerAssetDataLength >= 100,
- "INVALID_ASSET_DATA"
- );
- uint256 auctionBeginTimeSeconds = order.makerAssetData.readUint256(makerAssetDataLength - 64);
- uint256 auctionBeginAmount = order.makerAssetData.readUint256(makerAssetDataLength - 32);
- // Ensure the auction has a valid begin time
- require(
- order.expirationTimeSeconds > auctionBeginTimeSeconds,
- "INVALID_BEGIN_TIME"
- );
- uint256 auctionDurationSeconds = order.expirationTimeSeconds-auctionBeginTimeSeconds;
- // Ensure the auction goes from high to low
- uint256 minAmount = order.takerAssetAmount;
- require(
- auctionBeginAmount > minAmount,
- "INVALID_AMOUNT"
- );
- uint256 amountDelta = auctionBeginAmount-minAmount;
- // solhint-disable-next-line not-rely-on-time
- uint256 timestamp = block.timestamp;
- auctionDetails.beginTimeSeconds = auctionBeginTimeSeconds;
- auctionDetails.endTimeSeconds = order.expirationTimeSeconds;
- auctionDetails.beginAmount = auctionBeginAmount;
- auctionDetails.endAmount = minAmount;
- auctionDetails.currentTimeSeconds = timestamp;
-
- uint256 remainingDurationSeconds = order.expirationTimeSeconds-timestamp;
- if (timestamp < auctionBeginTimeSeconds) {
- // If the auction has not yet begun the current amount is the auctionBeginAmount
- auctionDetails.currentAmount = auctionBeginAmount;
- } else if (timestamp >= order.expirationTimeSeconds) {
- // If the auction has ended the current amount is the minAmount.
- // Auction end time is guaranteed by 0x Exchange due to the order expiration
- auctionDetails.currentAmount = minAmount;
- } else {
- auctionDetails.currentAmount = safeAdd(
- minAmount,
- safeDiv(
- safeMul(remainingDurationSeconds, amountDelta),
- auctionDurationSeconds
- )
- );
- }
- return auctionDetails;
- }
-}
diff --git a/contracts/extensions/contracts/Forwarder/Forwarder.sol b/contracts/extensions/contracts/Forwarder/Forwarder.sol
deleted file mode 100644
index 94dec40ed..000000000
--- a/contracts/extensions/contracts/Forwarder/Forwarder.sol
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
-
- 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 "./MixinWeth.sol";
-import "./MixinForwarderCore.sol";
-import "./libs/LibConstants.sol";
-import "./MixinAssets.sol";
-import "./MixinExchangeWrapper.sol";
-
-
-// solhint-disable no-empty-blocks
-contract Forwarder is
- LibConstants,
- MixinWeth,
- MixinAssets,
- MixinExchangeWrapper,
- MixinForwarderCore
-{
- constructor (
- address _exchange,
- bytes memory _zrxAssetData,
- bytes memory _wethAssetData
- )
- public
- LibConstants(
- _exchange,
- _zrxAssetData,
- _wethAssetData
- )
- MixinForwarderCore()
- {}
-}
diff --git a/contracts/extensions/contracts/Forwarder/MixinAssets.sol b/contracts/extensions/contracts/Forwarder/MixinAssets.sol
deleted file mode 100644
index 116cdf267..000000000
--- a/contracts/extensions/contracts/Forwarder/MixinAssets.sol
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
-
- 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 "./libs/LibConstants.sol";
-import "./mixins/MAssets.sol";
-
-
-contract MixinAssets is
- Ownable,
- LibConstants,
- MAssets
-{
- using LibBytes for bytes;
-
- bytes4 constant internal ERC20_TRANSFER_SELECTOR = bytes4(keccak256("transfer(address,uint256)"));
-
- /// @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 ERC20 token to withdraw.
- function withdrawAsset(
- bytes assetData,
- uint256 amount
- )
- external
- onlyOwner
- {
- transferAssetToSender(assetData, amount);
- }
-
- /// @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
- {
- 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.
- address token = assetData.readAddress(16);
- uint256 tokenId = assetData.readUint256(36);
-
- // Perform transfer.
- IERC721Token(token).transferFrom(
- address(this),
- msg.sender,
- tokenId
- );
- }
-}
diff --git a/contracts/extensions/contracts/Forwarder/MixinExchangeWrapper.sol b/contracts/extensions/contracts/Forwarder/MixinExchangeWrapper.sol
deleted file mode 100644
index cab26741d..000000000
--- a/contracts/extensions/contracts/Forwarder/MixinExchangeWrapper.sol
+++ /dev/null
@@ -1,260 +0,0 @@
-/*
-
- 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 "./mixins/MExchangeWrapper.sol";
-import "@0x/contracts-libs/contracts/libs/LibAbiEncoder.sol";
-import "@0x/contracts-libs/contracts/libs/LibOrder.sol";
-import "@0x/contracts-libs/contracts/libs/LibFillResults.sol";
-import "@0x/contracts-libs/contracts/libs/LibMath.sol";
-
-
-contract MixinExchangeWrapper is
- LibAbiEncoder,
- LibFillResults,
- LibMath,
- LibConstants,
- MExchangeWrapper
-{
- /// @dev Fills the input order.
- /// Returns false if the transaction would otherwise revert.
- /// @param order Order struct containing order specifications.
- /// @param takerAssetFillAmount Desired amount of takerAsset to sell.
- /// @param signature Proof that order has been created by maker.
- /// @return Amounts filled and fees paid by maker and taker.
- function fillOrderNoThrow(
- LibOrder.Order memory order,
- uint256 takerAssetFillAmount,
- bytes memory signature
- )
- internal
- returns (FillResults memory fillResults)
- {
- // ABI encode calldata for `fillOrder`
- bytes memory fillOrderCalldata = abiEncodeFillOrder(
- order,
- takerAssetFillAmount,
- signature
- );
-
- address exchange = address(EXCHANGE);
-
- // Call `fillOrder` and handle any exceptions gracefully
- assembly {
- let success := call(
- gas, // forward all gas
- exchange, // call address of Exchange contract
- 0, // transfer 0 wei
- add(fillOrderCalldata, 32), // pointer to start of input (skip array length in first 32 bytes)
- mload(fillOrderCalldata), // length of input
- fillOrderCalldata, // write output over input
- 128 // output size is 128 bytes
- )
- if success {
- mstore(fillResults, mload(fillOrderCalldata))
- mstore(add(fillResults, 32), mload(add(fillOrderCalldata, 32)))
- mstore(add(fillResults, 64), mload(add(fillOrderCalldata, 64)))
- mstore(add(fillResults, 96), mload(add(fillOrderCalldata, 96)))
- }
- }
- // fillResults values will be 0 by default if call was unsuccessful
- return fillResults;
- }
-
- /// @dev Synchronously executes multiple calls of fillOrder until total amount of WETH has been sold by taker.
- /// Returns false if the transaction would otherwise revert.
- /// @param orders Array of order specifications.
- /// @param wethSellAmount Desired amount of WETH to sell.
- /// @param signatures Proofs that orders have been signed by makers.
- /// @return Amounts filled and fees paid by makers and taker.
- function marketSellWeth(
- LibOrder.Order[] memory orders,
- uint256 wethSellAmount,
- bytes[] memory signatures
- )
- internal
- returns (FillResults memory totalFillResults)
- {
- bytes memory makerAssetData = orders[0].makerAssetData;
- bytes memory wethAssetData = WETH_ASSET_DATA;
-
- uint256 ordersLength = orders.length;
- for (uint256 i = 0; i != ordersLength; i++) {
-
- // We assume that asset being bought by taker is the same for each order.
- // We assume that asset being sold by taker is WETH for each order.
- orders[i].makerAssetData = makerAssetData;
- orders[i].takerAssetData = wethAssetData;
-
- // Calculate the remaining amount of WETH to sell
- uint256 remainingTakerAssetFillAmount = safeSub(wethSellAmount, totalFillResults.takerAssetFilledAmount);
-
- // Attempt to sell the remaining amount of WETH
- FillResults memory singleFillResults = fillOrderNoThrow(
- orders[i],
- remainingTakerAssetFillAmount,
- signatures[i]
- );
-
- // Update amounts filled and fees paid by maker and taker
- addFillResults(totalFillResults, singleFillResults);
-
- // Stop execution if the entire amount of takerAsset has been sold
- if (totalFillResults.takerAssetFilledAmount >= wethSellAmount) {
- break;
- }
- }
- return totalFillResults;
- }
-
- /// @dev Synchronously executes multiple fill orders in a single transaction until total amount is bought by taker.
- /// Returns false if the transaction would otherwise revert.
- /// The asset being sold by taker must always be WETH.
- /// @param orders Array of order specifications.
- /// @param makerAssetFillAmount Desired amount of makerAsset to buy.
- /// @param signatures Proofs that orders have been signed by makers.
- /// @return Amounts filled and fees paid by makers and taker.
- function marketBuyExactAmountWithWeth(
- LibOrder.Order[] memory orders,
- uint256 makerAssetFillAmount,
- bytes[] memory signatures
- )
- internal
- returns (FillResults memory totalFillResults)
- {
- bytes memory makerAssetData = orders[0].makerAssetData;
- bytes memory wethAssetData = WETH_ASSET_DATA;
-
- uint256 ordersLength = orders.length;
- for (uint256 i = 0; i != ordersLength; i++) {
-
- // We assume that asset being bought by taker is the same for each order.
- // We assume that asset being sold by taker is WETH for each order.
- orders[i].makerAssetData = makerAssetData;
- orders[i].takerAssetData = wethAssetData;
-
- // Calculate the remaining amount of makerAsset to buy
- uint256 remainingMakerAssetFillAmount = safeSub(makerAssetFillAmount, totalFillResults.makerAssetFilledAmount);
-
- // Convert the remaining amount of makerAsset to buy into remaining amount
- // of takerAsset to sell, assuming entire amount can be sold in the current order.
- // We round up because the exchange rate computed by fillOrder rounds in favor
- // of the Maker. In this case we want to overestimate the amount of takerAsset.
- uint256 remainingTakerAssetFillAmount = getPartialAmountCeil(
- orders[i].takerAssetAmount,
- orders[i].makerAssetAmount,
- remainingMakerAssetFillAmount
- );
-
- // Attempt to sell the remaining amount of takerAsset
- FillResults memory singleFillResults = fillOrderNoThrow(
- orders[i],
- remainingTakerAssetFillAmount,
- signatures[i]
- );
-
- // Update amounts filled and fees paid by maker and taker
- addFillResults(totalFillResults, singleFillResults);
-
- // Stop execution if the entire amount of makerAsset has been bought
- uint256 makerAssetFilledAmount = totalFillResults.makerAssetFilledAmount;
- if (makerAssetFilledAmount >= makerAssetFillAmount) {
- break;
- }
- }
-
- require(
- makerAssetFilledAmount >= makerAssetFillAmount,
- "COMPLETE_FILL_FAILED"
- );
- return totalFillResults;
- }
-
- /// @dev Buys zrxBuyAmount of ZRX fee tokens, taking into account ZRX fees for each order. This will guarantee
- /// that at least zrxBuyAmount of ZRX is purchased (sometimes slightly over due to rounding issues).
- /// It is possible that a request to buy 200 ZRX will require purchasing 202 ZRX
- /// as 2 ZRX is required to purchase the 200 ZRX fee tokens. This guarantees at least 200 ZRX for future purchases.
- /// The asset being sold by taker must always be WETH.
- /// @param orders Array of order specifications containing ZRX as makerAsset and WETH as takerAsset.
- /// @param zrxBuyAmount Desired amount of ZRX to buy.
- /// @param signatures Proofs that orders have been created by makers.
- /// @return totalFillResults Amounts filled and fees paid by maker and taker.
- function marketBuyExactZrxWithWeth(
- LibOrder.Order[] memory orders,
- uint256 zrxBuyAmount,
- bytes[] memory signatures
- )
- internal
- returns (FillResults memory totalFillResults)
- {
- // Do nothing if zrxBuyAmount == 0
- if (zrxBuyAmount == 0) {
- return totalFillResults;
- }
-
- bytes memory zrxAssetData = ZRX_ASSET_DATA;
- bytes memory wethAssetData = WETH_ASSET_DATA;
- uint256 zrxPurchased = 0;
-
- uint256 ordersLength = orders.length;
- for (uint256 i = 0; i != ordersLength; i++) {
-
- // All of these are ZRX/WETH, so we can drop the respective assetData from calldata.
- orders[i].makerAssetData = zrxAssetData;
- orders[i].takerAssetData = wethAssetData;
-
- // Calculate the remaining amount of ZRX to buy.
- uint256 remainingZrxBuyAmount = safeSub(zrxBuyAmount, zrxPurchased);
-
- // Convert the remaining amount of ZRX to buy into remaining amount
- // of WETH to sell, assuming entire amount can be sold in the current order.
- // We round up because the exchange rate computed by fillOrder rounds in favor
- // of the Maker. In this case we want to overestimate the amount of takerAsset.
- uint256 remainingWethSellAmount = getPartialAmountCeil(
- orders[i].takerAssetAmount,
- safeSub(orders[i].makerAssetAmount, orders[i].takerFee), // our exchange rate after fees
- remainingZrxBuyAmount
- );
-
- // Attempt to sell the remaining amount of WETH.
- FillResults memory singleFillResult = fillOrderNoThrow(
- orders[i],
- remainingWethSellAmount,
- signatures[i]
- );
-
- // Update amounts filled and fees paid by maker and taker.
- addFillResults(totalFillResults, singleFillResult);
- zrxPurchased = safeSub(totalFillResults.makerAssetFilledAmount, totalFillResults.takerFeePaid);
-
- // Stop execution if the entire amount of ZRX has been bought.
- if (zrxPurchased >= zrxBuyAmount) {
- break;
- }
- }
-
- require(
- zrxPurchased >= zrxBuyAmount,
- "COMPLETE_FILL_FAILED"
- );
- return totalFillResults;
- }
-}
diff --git a/contracts/extensions/contracts/Forwarder/MixinForwarderCore.sol b/contracts/extensions/contracts/Forwarder/MixinForwarderCore.sol
deleted file mode 100644
index 11c0147a5..000000000
--- a/contracts/extensions/contracts/Forwarder/MixinForwarderCore.sol
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
-
- 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 "./mixins/MWeth.sol";
-import "./mixins/MAssets.sol";
-import "./mixins/MExchangeWrapper.sol";
-import "./interfaces/IForwarderCore.sol";
-import "@0x/contracts-utils/contracts/utils/LibBytes/LibBytes.sol";
-import "@0x/contracts-libs/contracts/libs/LibOrder.sol";
-import "@0x/contracts-libs/contracts/libs/LibFillResults.sol";
-import "@0x/contracts-libs/contracts/libs/LibMath.sol";
-
-
-contract MixinForwarderCore is
- LibFillResults,
- LibMath,
- LibConstants,
- MWeth,
- MAssets,
- MExchangeWrapper,
- IForwarderCore
-{
- using LibBytes for bytes;
-
- /// @dev Constructor approves ERC20 proxy to transfer ZRX and WETH on this contract's behalf.
- constructor ()
- public
- {
- address proxyAddress = EXCHANGE.getAssetProxy(ERC20_DATA_ID);
- require(
- proxyAddress != address(0),
- "UNREGISTERED_ASSET_PROXY"
- );
- ETHER_TOKEN.approve(proxyAddress, MAX_UINT);
- ZRX_TOKEN.approve(proxyAddress, MAX_UINT);
- }
-
- /// @dev Purchases as much of orders' makerAssets as possible by selling up to 95% of transaction's ETH value.
- /// Any ZRX required to pay fees for primary orders will automatically be purchased by this contract.
- /// 5% of ETH value is reserved for paying fees to order feeRecipients (in ZRX) and forwarding contract feeRecipient (in ETH).
- /// Any ETH not spent will be refunded to sender.
- /// @param orders Array of order specifications used containing desired makerAsset and WETH as takerAsset.
- /// @param signatures Proofs that orders have been created by makers.
- /// @param feeOrders Array of order specifications containing ZRX as makerAsset and WETH as takerAsset. Used to purchase ZRX for primary order fees.
- /// @param feeSignatures Proofs that feeOrders have been created by makers.
- /// @param feePercentage Percentage of WETH sold that will payed as fee to forwarding contract feeRecipient.
- /// @param feeRecipient Address that will receive ETH when orders are filled.
- /// @return Amounts filled and fees paid by maker and taker for both sets of orders.
- function marketSellOrdersWithEth(
- LibOrder.Order[] memory orders,
- bytes[] memory signatures,
- LibOrder.Order[] memory feeOrders,
- bytes[] memory feeSignatures,
- uint256 feePercentage,
- address feeRecipient
- )
- public
- payable
- returns (
- FillResults memory orderFillResults,
- FillResults memory feeOrderFillResults
- )
- {
- // Convert ETH to WETH.
- convertEthToWeth();
-
- uint256 wethSellAmount;
- uint256 zrxBuyAmount;
- uint256 makerAssetAmountPurchased;
- if (orders[0].makerAssetData.equals(ZRX_ASSET_DATA)) {
- // Calculate amount of WETH that won't be spent on ETH fees.
- wethSellAmount = getPartialAmountFloor(
- PERCENTAGE_DENOMINATOR,
- safeAdd(PERCENTAGE_DENOMINATOR, feePercentage),
- msg.value
- );
- // Market sell available WETH.
- // ZRX fees are paid with this contract's balance.
- orderFillResults = marketSellWeth(
- orders,
- wethSellAmount,
- signatures
- );
- // The fee amount must be deducted from the amount transfered back to sender.
- makerAssetAmountPurchased = safeSub(orderFillResults.makerAssetFilledAmount, orderFillResults.takerFeePaid);
- } else {
- // 5% of WETH is reserved for filling feeOrders and paying feeRecipient.
- wethSellAmount = getPartialAmountFloor(
- MAX_WETH_FILL_PERCENTAGE,
- PERCENTAGE_DENOMINATOR,
- msg.value
- );
- // Market sell 95% of WETH.
- // ZRX fees are payed with this contract's balance.
- orderFillResults = marketSellWeth(
- orders,
- wethSellAmount,
- signatures
- );
- // Buy back all ZRX spent on fees.
- zrxBuyAmount = orderFillResults.takerFeePaid;
- feeOrderFillResults = marketBuyExactZrxWithWeth(
- feeOrders,
- zrxBuyAmount,
- feeSignatures
- );
- makerAssetAmountPurchased = orderFillResults.makerAssetFilledAmount;
- }
-
- // Transfer feePercentage of total ETH spent on primary orders to feeRecipient.
- // Refund remaining ETH to msg.sender.
- transferEthFeeAndRefund(
- orderFillResults.takerAssetFilledAmount,
- feeOrderFillResults.takerAssetFilledAmount,
- feePercentage,
- feeRecipient
- );
-
- // Transfer purchased assets to msg.sender.
- transferAssetToSender(orders[0].makerAssetData, makerAssetAmountPurchased);
- }
-
- /// @dev Attempt to purchase makerAssetFillAmount of makerAsset by selling ETH provided with transaction.
- /// Any ZRX required to pay fees for primary orders will automatically be purchased by this contract.
- /// Any ETH not spent will be refunded to sender.
- /// @param orders Array of order specifications used containing desired makerAsset and WETH as takerAsset.
- /// @param makerAssetFillAmount Desired amount of makerAsset to purchase.
- /// @param signatures Proofs that orders have been created by makers.
- /// @param feeOrders Array of order specifications containing ZRX as makerAsset and WETH as takerAsset. Used to purchase ZRX for primary order fees.
- /// @param feeSignatures Proofs that feeOrders have been created by makers.
- /// @param feePercentage Percentage of WETH sold that will payed as fee to forwarding contract feeRecipient.
- /// @param feeRecipient Address that will receive ETH when orders are filled.
- /// @return Amounts filled and fees paid by maker and taker for both sets of orders.
- function marketBuyOrdersWithEth(
- LibOrder.Order[] memory orders,
- uint256 makerAssetFillAmount,
- bytes[] memory signatures,
- LibOrder.Order[] memory feeOrders,
- bytes[] memory feeSignatures,
- uint256 feePercentage,
- address feeRecipient
- )
- public
- payable
- returns (
- FillResults memory orderFillResults,
- FillResults memory feeOrderFillResults
- )
- {
- // Convert ETH to WETH.
- convertEthToWeth();
-
- uint256 zrxBuyAmount;
- uint256 makerAssetAmountPurchased;
- if (orders[0].makerAssetData.equals(ZRX_ASSET_DATA)) {
- // If the makerAsset is ZRX, it is not necessary to pay fees out of this
- // contracts's ZRX balance because fees are factored into the price of the order.
- orderFillResults = marketBuyExactZrxWithWeth(
- orders,
- makerAssetFillAmount,
- signatures
- );
- // The fee amount must be deducted from the amount transfered back to sender.
- makerAssetAmountPurchased = safeSub(orderFillResults.makerAssetFilledAmount, orderFillResults.takerFeePaid);
- } else {
- // Attemp to purchase desired amount of makerAsset.
- // ZRX fees are payed with this contract's balance.
- orderFillResults = marketBuyExactAmountWithWeth(
- orders,
- makerAssetFillAmount,
- signatures
- );
- // Buy back all ZRX spent on fees.
- zrxBuyAmount = orderFillResults.takerFeePaid;
- feeOrderFillResults = marketBuyExactZrxWithWeth(
- feeOrders,
- zrxBuyAmount,
- feeSignatures
- );
- makerAssetAmountPurchased = orderFillResults.makerAssetFilledAmount;
- }
-
- // Transfer feePercentage of total ETH spent on primary orders to feeRecipient.
- // Refund remaining ETH to msg.sender.
- transferEthFeeAndRefund(
- orderFillResults.takerAssetFilledAmount,
- feeOrderFillResults.takerAssetFilledAmount,
- feePercentage,
- feeRecipient
- );
-
- // Transfer purchased assets to msg.sender.
- transferAssetToSender(orders[0].makerAssetData, makerAssetAmountPurchased);
- }
-}
diff --git a/contracts/extensions/contracts/Forwarder/MixinWeth.sol b/contracts/extensions/contracts/Forwarder/MixinWeth.sol
deleted file mode 100644
index 25a35f47b..000000000
--- a/contracts/extensions/contracts/Forwarder/MixinWeth.sol
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
-
- 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-libs/contracts/libs/LibMath.sol";
-import "./libs/LibConstants.sol";
-import "./mixins/MWeth.sol";
-
-
-contract MixinWeth is
- LibMath,
- LibConstants,
- MWeth
-{
- /// @dev Default payabale function, this allows us to withdraw WETH
- function ()
- public
- payable
- {
- require(
- msg.sender == address(ETHER_TOKEN),
- "DEFAULT_FUNCTION_WETH_CONTRACT_ONLY"
- );
- }
-
- /// @dev Converts message call's ETH value into WETH.
- function convertEthToWeth()
- internal
- {
- require(
- msg.value > 0,
- "INVALID_MSG_VALUE"
- );
- ETHER_TOKEN.deposit.value(msg.value)();
- }
-
- /// @dev Transfers feePercentage of WETH spent on primary orders to feeRecipient.
- /// Refunds any excess ETH to msg.sender.
- /// @param wethSoldExcludingFeeOrders Amount of WETH sold when filling primary orders.
- /// @param wethSoldForZrx Amount of WETH sold when purchasing ZRX required for primary order fees.
- /// @param feePercentage Percentage of WETH sold that will payed as fee to forwarding contract feeRecipient.
- /// @param feeRecipient Address that will receive ETH when orders are filled.
- function transferEthFeeAndRefund(
- uint256 wethSoldExcludingFeeOrders,
- uint256 wethSoldForZrx,
- uint256 feePercentage,
- address feeRecipient
- )
- internal
- {
- // Ensure feePercentage is less than 5%.
- require(
- feePercentage <= MAX_FEE_PERCENTAGE,
- "FEE_PERCENTAGE_TOO_LARGE"
- );
-
- // Ensure that no extra WETH owned by this contract has been sold.
- uint256 wethSold = safeAdd(wethSoldExcludingFeeOrders, wethSoldForZrx);
- require(
- wethSold <= msg.value,
- "OVERSOLD_WETH"
- );
-
- // Calculate amount of WETH that hasn't been sold.
- uint256 wethRemaining = safeSub(msg.value, wethSold);
-
- // Calculate ETH fee to pay to feeRecipient.
- uint256 ethFee = getPartialAmountFloor(
- feePercentage,
- PERCENTAGE_DENOMINATOR,
- wethSoldExcludingFeeOrders
- );
-
- // Ensure fee is less than amount of WETH remaining.
- require(
- ethFee <= wethRemaining,
- "INSUFFICIENT_ETH_REMAINING"
- );
-
- // Do nothing if no WETH remaining
- if (wethRemaining > 0) {
- // Convert remaining WETH to ETH
- ETHER_TOKEN.withdraw(wethRemaining);
-
- // Pay ETH to feeRecipient
- if (ethFee > 0) {
- feeRecipient.transfer(ethFee);
- }
-
- // Refund remaining ETH to msg.sender.
- uint256 ethRefund = safeSub(wethRemaining, ethFee);
- if (ethRefund > 0) {
- msg.sender.transfer(ethRefund);
- }
- }
- }
-}
diff --git a/contracts/extensions/contracts/Forwarder/interfaces/IAssets.sol b/contracts/extensions/contracts/Forwarder/interfaces/IAssets.sol
deleted file mode 100644
index cebfd3706..000000000
--- a/contracts/extensions/contracts/Forwarder/interfaces/IAssets.sol
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
-
- 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 ERC20 token to withdraw.
- function withdrawAsset(
- bytes assetData,
- uint256 amount
- )
- external;
-}
diff --git a/contracts/extensions/contracts/Forwarder/interfaces/IForwarder.sol b/contracts/extensions/contracts/Forwarder/interfaces/IForwarder.sol
deleted file mode 100644
index 6ce8a1d31..000000000
--- a/contracts/extensions/contracts/Forwarder/interfaces/IForwarder.sol
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
-
- 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 "./IForwarderCore.sol";
-import "./IAssets.sol";
-
-
-// solhint-disable no-empty-blocks
-contract IForwarder is
- IForwarderCore,
- IAssets
-{}
diff --git a/contracts/extensions/contracts/Forwarder/interfaces/IForwarderCore.sol b/contracts/extensions/contracts/Forwarder/interfaces/IForwarderCore.sol
deleted file mode 100644
index 7f62722e7..000000000
--- a/contracts/extensions/contracts/Forwarder/interfaces/IForwarderCore.sol
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
-
- 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";
-import "@0x/contracts-libs/contracts/libs/LibFillResults.sol";
-
-
-contract IForwarderCore {
-
- /// @dev Purchases as much of orders' makerAssets as possible by selling up to 95% of transaction's ETH value.
- /// Any ZRX required to pay fees for primary orders will automatically be purchased by this contract.
- /// 5% of ETH value is reserved for paying fees to order feeRecipients (in ZRX) and forwarding contract feeRecipient (in ETH).
- /// Any ETH not spent will be refunded to sender.
- /// @param orders Array of order specifications used containing desired makerAsset and WETH as takerAsset.
- /// @param signatures Proofs that orders have been created by makers.
- /// @param feeOrders Array of order specifications containing ZRX as makerAsset and WETH as takerAsset. Used to purchase ZRX for primary order fees.
- /// @param feeSignatures Proofs that feeOrders have been created by makers.
- /// @param feePercentage Percentage of WETH sold that will payed as fee to forwarding contract feeRecipient.
- /// @param feeRecipient Address that will receive ETH when orders are filled.
- /// @return Amounts filled and fees paid by maker and taker for both sets of orders.
- function marketSellOrdersWithEth(
- LibOrder.Order[] memory orders,
- bytes[] memory signatures,
- LibOrder.Order[] memory feeOrders,
- bytes[] memory feeSignatures,
- uint256 feePercentage,
- address feeRecipient
- )
- public
- payable
- returns (
- LibFillResults.FillResults memory orderFillResults,
- LibFillResults.FillResults memory feeOrderFillResults
- );
-
- /// @dev Attempt to purchase makerAssetFillAmount of makerAsset by selling ETH provided with transaction.
- /// Any ZRX required to pay fees for primary orders will automatically be purchased by this contract.
- /// Any ETH not spent will be refunded to sender.
- /// @param orders Array of order specifications used containing desired makerAsset and WETH as takerAsset.
- /// @param makerAssetFillAmount Desired amount of makerAsset to purchase.
- /// @param signatures Proofs that orders have been created by makers.
- /// @param feeOrders Array of order specifications containing ZRX as makerAsset and WETH as takerAsset. Used to purchase ZRX for primary order fees.
- /// @param feeSignatures Proofs that feeOrders have been created by makers.
- /// @param feePercentage Percentage of WETH sold that will payed as fee to forwarding contract feeRecipient.
- /// @param feeRecipient Address that will receive ETH when orders are filled.
- /// @return Amounts filled and fees paid by maker and taker for both sets of orders.
- function marketBuyOrdersWithEth(
- LibOrder.Order[] memory orders,
- uint256 makerAssetFillAmount,
- bytes[] memory signatures,
- LibOrder.Order[] memory feeOrders,
- bytes[] memory feeSignatures,
- uint256 feePercentage,
- address feeRecipient
- )
- public
- payable
- returns (
- LibFillResults.FillResults memory orderFillResults,
- LibFillResults.FillResults memory feeOrderFillResults
- );
-}
diff --git a/contracts/extensions/contracts/Forwarder/libs/LibConstants.sol b/contracts/extensions/contracts/Forwarder/libs/LibConstants.sol
deleted file mode 100644
index 0d2f6e36d..000000000
--- a/contracts/extensions/contracts/Forwarder/libs/LibConstants.sol
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
-
- 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-interfaces/contracts/protocol/Exchange/IExchange.sol";
-import "@0x/contracts-tokens/contracts/tokens/EtherToken/IEtherToken.sol";
-import "@0x/contracts-tokens/contracts/tokens/ERC20Token/IERC20Token.sol";
-
-
-contract LibConstants {
-
- using LibBytes for bytes;
-
- bytes4 constant internal ERC20_DATA_ID = bytes4(keccak256("ERC20Token(address)"));
- bytes4 constant internal ERC721_DATA_ID = bytes4(keccak256("ERC721Token(address,uint256)"));
- uint256 constant internal MAX_UINT = 2**256 - 1;
- uint256 constant internal PERCENTAGE_DENOMINATOR = 10**18;
- uint256 constant internal MAX_FEE_PERCENTAGE = 5 * PERCENTAGE_DENOMINATOR / 100; // 5%
- uint256 constant internal MAX_WETH_FILL_PERCENTAGE = 95 * PERCENTAGE_DENOMINATOR / 100; // 95%
-
- // solhint-disable var-name-mixedcase
- IExchange internal EXCHANGE;
- IEtherToken internal ETHER_TOKEN;
- IERC20Token internal ZRX_TOKEN;
- bytes internal ZRX_ASSET_DATA;
- bytes internal WETH_ASSET_DATA;
- // solhint-enable var-name-mixedcase
-
- constructor (
- address _exchange,
- bytes memory _zrxAssetData,
- bytes memory _wethAssetData
- )
- public
- {
- EXCHANGE = IExchange(_exchange);
- ZRX_ASSET_DATA = _zrxAssetData;
- WETH_ASSET_DATA = _wethAssetData;
-
- address etherToken = _wethAssetData.readAddress(16);
- address zrxToken = _zrxAssetData.readAddress(16);
- ETHER_TOKEN = IEtherToken(etherToken);
- ZRX_TOKEN = IERC20Token(zrxToken);
- }
-}
diff --git a/contracts/extensions/contracts/Forwarder/libs/LibForwarderErrors.sol b/contracts/extensions/contracts/Forwarder/libs/LibForwarderErrors.sol
deleted file mode 100644
index 7a95b78a0..000000000
--- a/contracts/extensions/contracts/Forwarder/libs/LibForwarderErrors.sol
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
-
- 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.
-
-*/
-
-// solhint-disable
-pragma solidity ^0.4.24;
-
-
-/// This contract is intended to serve as a reference, but is not actually used for efficiency reasons.
-contract LibForwarderErrors {
- string constant FEE_PERCENTAGE_TOO_LARGE = "FEE_PROPORTION_TOO_LARGE"; // Provided fee percentage greater than 5%.
- string constant INSUFFICIENT_ETH_REMAINING = "INSUFFICIENT_ETH_REMAINING"; // Not enough ETH remaining to pay feeRecipient.
- 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_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/contracts/extensions/contracts/Forwarder/mixins/MAssets.sol b/contracts/extensions/contracts/Forwarder/mixins/MAssets.sol
deleted file mode 100644
index 1757b37fb..000000000
--- a/contracts/extensions/contracts/Forwarder/mixins/MAssets.sol
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
-
- 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;
-}
diff --git a/contracts/extensions/contracts/Forwarder/mixins/MExchangeWrapper.sol b/contracts/extensions/contracts/Forwarder/mixins/MExchangeWrapper.sol
deleted file mode 100644
index 143f888b1..000000000
--- a/contracts/extensions/contracts/Forwarder/mixins/MExchangeWrapper.sol
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
-
- 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";
-import "@0x/contracts-libs/contracts/libs/LibFillResults.sol";
-
-
-contract MExchangeWrapper {
-
- /// @dev Fills the input order.
- /// Returns false if the transaction would otherwise revert.
- /// @param order Order struct containing order specifications.
- /// @param takerAssetFillAmount Desired amount of takerAsset to sell.
- /// @param signature Proof that order has been created by maker.
- /// @return Amounts filled and fees paid by maker and taker.
- function fillOrderNoThrow(
- LibOrder.Order memory order,
- uint256 takerAssetFillAmount,
- bytes memory signature
- )
- internal
- returns (LibFillResults.FillResults memory fillResults);
-
- /// @dev Synchronously executes multiple calls of fillOrder until total amount of WETH has been sold by taker.
- /// Returns false if the transaction would otherwise revert.
- /// @param orders Array of order specifications.
- /// @param wethSellAmount Desired amount of WETH to sell.
- /// @param signatures Proofs that orders have been signed by makers.
- /// @return Amounts filled and fees paid by makers and taker.
- function marketSellWeth(
- LibOrder.Order[] memory orders,
- uint256 wethSellAmount,
- bytes[] memory signatures
- )
- internal
- returns (LibFillResults.FillResults memory totalFillResults);
-
- /// @dev Synchronously executes multiple fill orders in a single transaction until total amount is bought by taker.
- /// Returns false if the transaction would otherwise revert.
- /// The asset being sold by taker must always be WETH.
- /// @param orders Array of order specifications.
- /// @param makerAssetFillAmount Desired amount of makerAsset to buy.
- /// @param signatures Proofs that orders have been signed by makers.
- /// @return Amounts filled and fees paid by makers and taker.
- function marketBuyExactAmountWithWeth(
- LibOrder.Order[] memory orders,
- uint256 makerAssetFillAmount,
- bytes[] memory signatures
- )
- internal
- returns (LibFillResults.FillResults memory totalFillResults);
-
- /// @dev Buys zrxBuyAmount of ZRX fee tokens, taking into account ZRX fees for each order. This will guarantee
- /// that at least zrxBuyAmount of ZRX is purchased (sometimes slightly over due to rounding issues).
- /// It is possible that a request to buy 200 ZRX will require purchasing 202 ZRX
- /// as 2 ZRX is required to purchase the 200 ZRX fee tokens. This guarantees at least 200 ZRX for future purchases.
- /// The asset being sold by taker must always be WETH.
- /// @param orders Array of order specifications containing ZRX as makerAsset and WETH as takerAsset.
- /// @param zrxBuyAmount Desired amount of ZRX to buy.
- /// @param signatures Proofs that orders have been created by makers.
- /// @return totalFillResults Amounts filled and fees paid by maker and taker.
- function marketBuyExactZrxWithWeth(
- LibOrder.Order[] memory orders,
- uint256 zrxBuyAmount,
- bytes[] memory signatures
- )
- internal
- returns (LibFillResults.FillResults memory totalFillResults);
-}
diff --git a/contracts/extensions/contracts/Forwarder/mixins/MWeth.sol b/contracts/extensions/contracts/Forwarder/mixins/MWeth.sol
deleted file mode 100644
index 15d66942f..000000000
--- a/contracts/extensions/contracts/Forwarder/mixins/MWeth.sol
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
-
- 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 MWeth {
-
- /// @dev Converts message call's ETH value into WETH.
- function convertEthToWeth()
- internal;
-
- /// @dev Transfers feePercentage of WETH spent on primary orders to feeRecipient.
- /// Refunds any excess ETH to msg.sender.
- /// @param wethSoldExcludingFeeOrders Amount of WETH sold when filling primary orders.
- /// @param wethSoldForZrx Amount of WETH sold when purchasing ZRX required for primary order fees.
- /// @param feePercentage Percentage of WETH sold that will payed as fee to forwarding contract feeRecipient.
- /// @param feeRecipient Address that will receive ETH when orders are filled.
- function transferEthFeeAndRefund(
- uint256 wethSoldExcludingFeeOrders,
- uint256 wethSoldForZrx,
- uint256 feePercentage,
- address feeRecipient
- )
- internal;
-}
diff --git a/contracts/extensions/contracts/OrderMatcher/MixinAssets.sol b/contracts/extensions/contracts/OrderMatcher/MixinAssets.sol
deleted file mode 100644
index f0f91cfc0..000000000
--- a/contracts/extensions/contracts/OrderMatcher/MixinAssets.sol
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
-
- 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
deleted file mode 100644
index 1787deb59..000000000
--- a/contracts/extensions/contracts/OrderMatcher/MixinMatchOrders.sol
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
-
- 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
deleted file mode 100644
index 4879b7bca..000000000
--- a/contracts/extensions/contracts/OrderMatcher/OrderMatcher.sol
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
-
- 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
deleted file mode 100644
index 9fcc0023a..000000000
--- a/contracts/extensions/contracts/OrderMatcher/interfaces/IAssets.sol
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
-
- 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
deleted file mode 100644
index 1443c73b9..000000000
--- a/contracts/extensions/contracts/OrderMatcher/interfaces/IMatchOrders.sol
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
-
- 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
deleted file mode 100644
index 75f26dca6..000000000
--- a/contracts/extensions/contracts/OrderMatcher/interfaces/IOrderMatcher.sol
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
-
- 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
deleted file mode 100644
index c1a86a9c7..000000000
--- a/contracts/extensions/contracts/OrderMatcher/libs/LibConstants.sol
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
-
- 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
deleted file mode 100644
index 6ea7a3290..000000000
--- a/contracts/extensions/contracts/OrderMatcher/mixins/MAssets.sol
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
-
- 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/extensions/contracts/OrderValidator/OrderValidator.sol b/contracts/extensions/contracts/OrderValidator/OrderValidator.sol
deleted file mode 100644
index 33dd1326c..000000000
--- a/contracts/extensions/contracts/OrderValidator/OrderValidator.sol
+++ /dev/null
@@ -1,218 +0,0 @@
-/*
-
- 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-interfaces/contracts/protocol/Exchange/IExchange.sol";
-import "@0x/contracts-libs/contracts/libs/LibOrder.sol";
-import "@0x/contracts-tokens/contracts/tokens/ERC20Token/IERC20Token.sol";
-import "@0x/contracts-tokens/contracts/tokens/ERC721Token/IERC721Token.sol";
-import "@0x/contracts-utils/contracts/utils/LibBytes/LibBytes.sol";
-
-
-contract OrderValidator {
-
- using LibBytes for bytes;
-
- bytes4 constant internal ERC20_DATA_ID = bytes4(keccak256("ERC20Token(address)"));
- bytes4 constant internal ERC721_DATA_ID = bytes4(keccak256("ERC721Token(address,uint256)"));
-
- 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);
-
- // 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/contracts/extensions/package.json b/contracts/extensions/package.json
deleted file mode 100644
index 14492af8f..000000000
--- a/contracts/extensions/package.json
+++ /dev/null
@@ -1,93 +0,0 @@
-{
- "name": "@0x/contracts-extensions",
- "version": "1.2.3",
- "engines": {
- "node": ">=6.12"
- },
- "description": "Smart contract extensions of 0x protocol",
- "main": "lib/src/index.js",
- "directories": {
- "test": "test"
- },
- "scripts": {
- "build": "yarn pre_build && tsc -b",
- "build:ci": "yarn build",
- "pre_build": "run-s compile generate_contract_wrappers",
- "test": "yarn run_mocha",
- "rebuild_and_test": "run-s build test",
- "test:coverage": "SOLIDITY_COVERAGE=true run-s build run_mocha coverage:report:text coverage:report:lcov",
- "test:profiler": "SOLIDITY_PROFILER=true run-s build run_mocha profiler:report:html",
- "test:trace": "SOLIDITY_REVERT_TRACE=true run-s build run_mocha",
- "run_mocha": "mocha --require source-map-support/register --require make-promises-safe 'lib/test/**/*.js' --timeout 100000 --bail --exit",
- "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",
- "coverage:report:text": "istanbul report text",
- "coverage:report:html": "istanbul report html && open coverage/index.html",
- "profiler:report:html": "istanbul report html && open coverage/index.html",
- "coverage:report:lcov": "istanbul report lcov",
- "test:circleci": "yarn test",
- "lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol"
- },
- "config": {
- "abis": "generated-artifacts/@(BalanceThresholdFilter|DutchAuction|Forwarder|OrderMatcher|OrderValidator).json"
- },
- "repository": {
- "type": "git",
- "url": "https://github.com/0xProject/0x-monorepo.git"
- },
- "license": "Apache-2.0",
- "bugs": {
- "url": "https://github.com/0xProject/0x-monorepo/issues"
- },
- "homepage": "https://github.com/0xProject/0x-monorepo/contracts/extensions/README.md",
- "devDependencies": {
- "@0x/abi-gen": "^1.0.22",
- "@0x/contract-wrappers": "^5.0.1",
- "@0x/contracts-test-utils": "^2.0.1",
- "@0x/dev-utils": "^1.0.24",
- "@0x/sol-compiler": "^2.0.2",
- "@0x/subproviders": "^2.1.11",
- "@0x/tslint-config": "^2.0.2",
- "@types/bn.js": "^4.11.0",
- "@types/lodash": "4.14.104",
- "@types/node": "*",
- "@types/yargs": "^10.0.0",
- "chai": "^4.0.1",
- "chai-as-promised": "^7.1.0",
- "chai-bignumber": "^3.0.0",
- "dirty-chai": "^2.0.1",
- "ethereumjs-abi": "0.6.5",
- "make-promises-safe": "^1.1.0",
- "mocha": "^4.1.0",
- "npm-run-all": "^4.1.2",
- "shx": "^0.2.2",
- "solhint": "^1.4.1",
- "tslint": "5.11.0",
- "typescript": "3.0.1",
- "yargs": "^10.0.3"
- },
- "dependencies": {
- "@0x/base-contract": "^3.0.13",
- "@0x/contracts-interfaces": "^1.0.6",
- "@0x/contracts-libs": "^1.0.6",
- "@0x/contracts-protocol": "^2.2.3",
- "@0x/contracts-tokens": "^1.0.6",
- "@0x/contracts-utils": "^1.0.6",
- "@0x/order-utils": "^3.1.2",
- "@0x/types": "^1.5.2",
- "@0x/typescript-typings": "^3.0.8",
- "@0x/utils": "^3.0.1",
- "@0x/web3-wrapper": "^3.2.4",
- "@types/js-combinatorics": "^0.5.29",
- "bn.js": "^4.11.8",
- "ethereum-types": "^1.1.6",
- "ethereumjs-util": "^5.1.1",
- "lodash": "^4.17.5"
- },
- "publishConfig": {
- "access": "public"
- }
-}
diff --git a/contracts/extensions/src/artifacts/index.ts b/contracts/extensions/src/artifacts/index.ts
deleted file mode 100644
index 329d0f3f3..000000000
--- a/contracts/extensions/src/artifacts/index.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-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/index.ts b/contracts/extensions/src/index.ts
deleted file mode 100644
index d55f08ea2..000000000
--- a/contracts/extensions/src/index.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-export * from './artifacts';
-export * from './wrappers';
diff --git a/contracts/extensions/src/wrappers/index.ts b/contracts/extensions/src/wrappers/index.ts
deleted file mode 100644
index 65aec3ccd..000000000
--- a/contracts/extensions/src/wrappers/index.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-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/balance_threshold_filter.ts b/contracts/extensions/test/extensions/balance_threshold_filter.ts
deleted file mode 100644
index adeb7c422..000000000
--- a/contracts/extensions/test/extensions/balance_threshold_filter.ts
+++ /dev/null
@@ -1,1644 +0,0 @@
-import { BlockchainLifecycle } from '@0x/dev-utils';
-import { assetDataUtils } from '@0x/order-utils';
-import { Order, RevertReason, SignedOrder } from '@0x/types';
-import { BigNumber } from '@0x/utils';
-import { Web3Wrapper } from '@0x/web3-wrapper';
-import * as chai from 'chai';
-import { TransactionReceiptWithDecodedLogs } from 'ethereum-types';
-import * as _ from 'lodash';
-
-import {
- artifacts as protocolArtifacts,
- ERC20Wrapper,
- ERC721Wrapper,
- ExchangeContract,
- ExchangeWrapper,
-} from '@0x/contracts-protocol';
-import {
- chaiSetup,
- constants,
- ContractName,
- ERC20BalancesByOwner,
- expectTransactionFailedAsync,
- OrderFactory,
- OrderStatus,
- provider,
- TransactionFactory,
- txDefaults,
- web3Wrapper,
-} from '@0x/contracts-test-utils';
-import { DummyERC20TokenContract } from '@0x/contracts-tokens';
-
-import { BalanceThresholdFilterContract } from '../../generated-wrappers/balance_threshold_filter';
-import { artifacts } from '../../src/artifacts';
-import { BalanceThresholdWrapper } from '../utils/balance_threshold_wrapper';
-
-chaiSetup.configure();
-const expect = chai.expect;
-const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
-const DECIMALS_DEFAULT = 18;
-
-interface ValidatedAddressesLog {
- args: { addresses: string[] };
-}
-
-describe(ContractName.BalanceThresholdFilter, () => {
- const takerAssetAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(500), DECIMALS_DEFAULT);
- const makerAssetAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(1000), DECIMALS_DEFAULT);
- const takerAssetFillAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(250), DECIMALS_DEFAULT);
-
- let validMakerAddress: string;
- let validMakerAddress2: string;
- let owner: string;
- let validTakerAddress: string;
- let feeRecipientAddress: string;
- let invalidAddress: string;
- let defaultMakerAssetAddress: string;
- let defaultTakerAssetAddress: string;
- let zrxAssetData: string;
- let zrxToken: DummyERC20TokenContract;
- let exchangeInstance: ExchangeContract;
- let exchangeWrapper: ExchangeWrapper;
-
- let orderFactory: OrderFactory;
- let orderFactory2: OrderFactory;
- let invalidOrderFactory: OrderFactory;
- let erc20Wrapper: ERC20Wrapper;
- let erc20Balances: ERC20BalancesByOwner;
- let erc20TakerBalanceThresholdWrapper: BalanceThresholdWrapper;
- let erc721TakerBalanceThresholdWrapper: BalanceThresholdWrapper;
- let erc721MakerBalanceThresholdWrapper: BalanceThresholdWrapper;
- let erc721NonValidBalanceThresholdWrapper: BalanceThresholdWrapper;
-
- let defaultOrderParams: Partial<Order>;
- let validSignedOrder: SignedOrder;
- let validSignedOrder2: SignedOrder;
-
- let erc721BalanceThresholdFilterInstance: BalanceThresholdFilterContract;
- let erc20BalanceThresholdFilterInstance: BalanceThresholdFilterContract;
-
- const assertValidatedAddressesLog = async (
- txReceipt: TransactionReceiptWithDecodedLogs,
- expectedValidatedAddresses: string[],
- ) => {
- expect(txReceipt.logs.length).to.be.gte(1);
- const validatedAddressesLog = (txReceipt.logs[0] as any) as ValidatedAddressesLog;
- const validatedAddresses = validatedAddressesLog.args.addresses;
- // @HACK-hysz: Nested addresses are not translated to lower-case but this will change once
- // the new ABI Encoder/Decoder is used by the contract templates.
- const validatedAddressesNormalized: string[] = [];
- _.each(validatedAddresses, address => {
- const normalizedAddress = _.toLower(address);
- validatedAddressesNormalized.push(normalizedAddress);
- });
- expect(validatedAddressesNormalized).to.be.deep.equal(expectedValidatedAddresses);
- };
-
- before(async () => {
- // Create accounts
- await blockchainLifecycle.startAsync();
- const accounts = await web3Wrapper.getAvailableAddressesAsync();
- const usedAddresses = ([
- owner,
- validMakerAddress,
- validMakerAddress2,
- validTakerAddress,
- feeRecipientAddress,
- invalidAddress,
- ] = accounts);
- const takerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(validTakerAddress)];
- const makerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(validMakerAddress)];
- const secondMakerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(validMakerAddress2)];
- const invalidAddressPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(invalidAddress)];
- // Create wrappers
- erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner);
- const validAddresses = _.cloneDeepWith(usedAddresses);
- _.remove(validAddresses, (address: string) => {
- return address === invalidAddress;
- });
- const erc721Wrapper = new ERC721Wrapper(provider, validAddresses, owner);
- // Deploy ERC20 tokens
- const numDummyErc20ToDeploy = 4;
- let erc20TokenA: DummyERC20TokenContract;
- let erc20TokenB: DummyERC20TokenContract;
- let erc20BalanceThresholdAsset: DummyERC20TokenContract;
- [erc20TokenA, erc20TokenB, zrxToken, erc20BalanceThresholdAsset] = await erc20Wrapper.deployDummyTokensAsync(
- numDummyErc20ToDeploy,
- constants.DUMMY_TOKEN_DECIMALS,
- );
- defaultMakerAssetAddress = erc20TokenA.address;
- defaultTakerAssetAddress = erc20TokenB.address;
- zrxAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address);
- // Create proxies
- const erc20Proxy = await erc20Wrapper.deployProxyAsync();
- await erc20Wrapper.setBalancesAndAllowancesAsync();
- // Deploy Exchange contract
- exchangeInstance = await ExchangeContract.deployFrom0xArtifactAsync(
- protocolArtifacts.Exchange,
- provider,
- txDefaults,
- zrxAssetData,
- );
- exchangeWrapper = new ExchangeWrapper(exchangeInstance, provider);
- // Register proxies
- await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner);
- await erc20Proxy.addAuthorizedAddress.sendTransactionAsync(exchangeInstance.address, {
- from: owner,
- });
- // Deploy Balance Threshold Filters
- // One uses an ERC721 token as its balance threshold asset; the other uses an ERC20
- const erc721alanceThreshold = new BigNumber(1);
- await erc721Wrapper.deployProxyAsync();
- const [erc721BalanceThresholdAsset] = await erc721Wrapper.deployDummyTokensAsync();
- await erc721Wrapper.setBalancesAndAllowancesAsync();
- erc721BalanceThresholdFilterInstance = await BalanceThresholdFilterContract.deployFrom0xArtifactAsync(
- artifacts.BalanceThresholdFilter,
- provider,
- txDefaults,
- exchangeInstance.address,
- erc721BalanceThresholdAsset.address,
- erc721alanceThreshold,
- );
- const erc20BalanceThreshold = Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 10);
- erc20BalanceThresholdFilterInstance = await BalanceThresholdFilterContract.deployFrom0xArtifactAsync(
- artifacts.BalanceThresholdFilter,
- provider,
- txDefaults,
- exchangeInstance.address,
- erc20BalanceThresholdAsset.address,
- erc20BalanceThreshold,
- );
- // Default order parameters
- defaultOrderParams = {
- exchangeAddress: exchangeInstance.address,
- feeRecipientAddress,
- makerAssetData: assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress),
- takerAssetData: assetDataUtils.encodeERC20AssetData(defaultTakerAssetAddress),
- makerAssetAmount,
- takerAssetAmount,
- makerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), DECIMALS_DEFAULT),
- takerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(150), DECIMALS_DEFAULT),
- senderAddress: erc721BalanceThresholdFilterInstance.address,
- };
- // Create two order factories with valid makers (who meet the threshold balance), and
- // one factory for an invalid address (that does not meet the threshold balance)
- // Valid order factory #1
- const defaultOrderParams1 = {
- makerAddress: validMakerAddress,
- ...defaultOrderParams,
- };
- orderFactory = new OrderFactory(makerPrivateKey, defaultOrderParams1);
- // Valid order factory #2
- const defaultOrderParams2 = {
- makerAddress: validMakerAddress2,
- ...defaultOrderParams,
- };
- orderFactory2 = new OrderFactory(secondMakerPrivateKey, defaultOrderParams2);
- // Invalid order factory
- const defaultNonValidOrderParams = {
- makerAddress: invalidAddress,
- ...defaultOrderParams,
- };
- invalidOrderFactory = new OrderFactory(invalidAddressPrivateKey, defaultNonValidOrderParams);
- // Create Balance Thresold Wrappers
- erc20TakerBalanceThresholdWrapper = new BalanceThresholdWrapper(
- erc20BalanceThresholdFilterInstance,
- exchangeInstance,
- new TransactionFactory(takerPrivateKey, exchangeInstance.address),
- provider,
- );
- erc721TakerBalanceThresholdWrapper = new BalanceThresholdWrapper(
- erc721BalanceThresholdFilterInstance,
- exchangeInstance,
- new TransactionFactory(takerPrivateKey, exchangeInstance.address),
- provider,
- );
- erc721MakerBalanceThresholdWrapper = new BalanceThresholdWrapper(
- erc721BalanceThresholdFilterInstance,
- exchangeInstance,
- new TransactionFactory(makerPrivateKey, exchangeInstance.address),
- provider,
- );
- erc721NonValidBalanceThresholdWrapper = new BalanceThresholdWrapper(
- erc721BalanceThresholdFilterInstance,
- exchangeInstance,
- new TransactionFactory(invalidAddressPrivateKey, exchangeInstance.address),
- provider,
- );
- });
- beforeEach(async () => {
- await blockchainLifecycle.startAsync();
- });
- afterEach(async () => {
- await blockchainLifecycle.revertAsync();
- });
-
- describe('General Sanity Checks', () => {
- beforeEach(async () => {
- erc20Balances = await erc20Wrapper.getBalancesAsync();
- validSignedOrder = await orderFactory.newSignedOrderAsync();
- validSignedOrder2 = await orderFactory2.newSignedOrderAsync();
- });
- it('should transfer the correct amounts and validate both maker/taker when both maker and taker exceed the balance threshold of an ERC20 token', async () => {
- const validSignedOrderERC20Sender = await orderFactory.newSignedOrderAsync({
- ...defaultOrderParams,
- makerAddress: validMakerAddress,
- senderAddress: erc20TakerBalanceThresholdWrapper.getBalanceThresholdAddress(),
- });
- // Execute a valid fill
- const txReceipt = await erc20TakerBalanceThresholdWrapper.fillOrderAsync(
- validSignedOrderERC20Sender,
- validTakerAddress,
- { takerAssetFillAmount },
- );
- // Assert validated addresses
- const expectedValidatedAddresseses = [validSignedOrder.makerAddress, validTakerAddress];
- await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
- // Check balances
- const newBalances = await erc20Wrapper.getBalancesAsync();
- const makerAssetFillAmount = takerAssetFillAmount
- .times(validSignedOrder.makerAssetAmount)
- .dividedToIntegerBy(validSignedOrder.takerAssetAmount);
- const makerFeePaid = validSignedOrder.makerFee
- .times(makerAssetFillAmount)
- .dividedToIntegerBy(validSignedOrder.makerAssetAmount);
- const takerFeePaid = validSignedOrder.takerFee
- .times(makerAssetFillAmount)
- .dividedToIntegerBy(validSignedOrder.makerAssetAmount);
- expect(newBalances[validMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[validMakerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount),
- );
- expect(newBalances[validMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[validMakerAddress][defaultTakerAssetAddress].plus(takerAssetFillAmount),
- );
- expect(newBalances[validMakerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[validMakerAddress][zrxToken.address].minus(makerFeePaid),
- );
- expect(newBalances[validTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[validTakerAddress][defaultTakerAssetAddress].minus(takerAssetFillAmount),
- );
- expect(newBalances[validTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[validTakerAddress][defaultMakerAssetAddress].plus(makerAssetFillAmount),
- );
- expect(newBalances[validTakerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[validTakerAddress][zrxToken.address].minus(takerFeePaid),
- );
- expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[feeRecipientAddress][zrxToken.address].plus(makerFeePaid.plus(takerFeePaid)),
- );
- });
- it('should revert if the Exchange transaction function is not supported', async () => {
- // Create signed order without the fillOrder function selector
- const salt = new BigNumber(0);
- const badSelectorHex = '0x00000000';
- const signatureHex = '0x';
- // Call valid forwarder
- return expectTransactionFailedAsync(
- erc721BalanceThresholdFilterInstance.executeTransaction.sendTransactionAsync(
- salt,
- validTakerAddress,
- badSelectorHex,
- signatureHex,
- ),
- RevertReason.InvalidOrBlockedExchangeSelector,
- );
- });
- it('should revert if senderAddress is not set to the valid forwarding contract', async () => {
- // Create signed order with incorrect senderAddress
- const notBalanceThresholdFilterAddress = zrxToken.address;
- const signedOrderWithBadSenderAddress = await orderFactory.newSignedOrderAsync({
- senderAddress: notBalanceThresholdFilterAddress,
- });
- // Call valid forwarder
- return expectTransactionFailedAsync(
- erc721TakerBalanceThresholdWrapper.fillOrderAsync(signedOrderWithBadSenderAddress, validTakerAddress, {
- takerAssetFillAmount,
- }),
- RevertReason.FailedExecution,
- );
- });
- });
-
- describe('batchFillOrders', () => {
- beforeEach(async () => {
- erc20Balances = await erc20Wrapper.getBalancesAsync();
- validSignedOrder = await orderFactory.newSignedOrderAsync();
- validSignedOrder2 = await orderFactory2.newSignedOrderAsync();
- });
- it('should transfer the correct amounts and validate both makers/taker when both maker and taker meet the balance threshold', async () => {
- // Execute a valid fill
- const orders = [validSignedOrder, validSignedOrder2];
- const takerAssetFillAmounts = [takerAssetFillAmount, takerAssetFillAmount];
- const txReceipt = await erc721TakerBalanceThresholdWrapper.batchFillOrdersAsync(orders, validTakerAddress, {
- takerAssetFillAmounts,
- });
- // Assert validated addresses
- const expectedValidatedAddresseses = [
- validSignedOrder.makerAddress,
- validSignedOrder2.makerAddress,
- validTakerAddress,
- ];
- await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
- // Check balances
- const newBalances = await erc20Wrapper.getBalancesAsync();
- const cumulativeTakerAssetFillAmount = takerAssetFillAmount.times(2);
- const makerAssetFillAmount = takerAssetFillAmount
- .times(validSignedOrder.makerAssetAmount)
- .dividedToIntegerBy(validSignedOrder.takerAssetAmount);
- const makerFeePaid = validSignedOrder.makerFee
- .times(makerAssetFillAmount)
- .dividedToIntegerBy(validSignedOrder.makerAssetAmount);
- const takerFeePaid = validSignedOrder.takerFee
- .times(makerAssetFillAmount)
- .dividedToIntegerBy(validSignedOrder.makerAssetAmount)
- .times(2);
- // Maker #1
- expect(newBalances[validMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[validMakerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount),
- );
- expect(newBalances[validMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[validMakerAddress][defaultTakerAssetAddress].plus(takerAssetFillAmount),
- );
- expect(newBalances[validMakerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[validMakerAddress][zrxToken.address].minus(makerFeePaid),
- );
- // Maker #2
- expect(newBalances[validMakerAddress2][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[validMakerAddress2][defaultMakerAssetAddress].minus(makerAssetFillAmount),
- );
- expect(newBalances[validMakerAddress2][defaultTakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[validMakerAddress2][defaultTakerAssetAddress].plus(takerAssetFillAmount),
- );
- expect(newBalances[validMakerAddress2][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[validMakerAddress2][zrxToken.address].minus(makerFeePaid),
- );
- // Taker
- expect(newBalances[validTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[validTakerAddress][defaultTakerAssetAddress].minus(cumulativeTakerAssetFillAmount),
- );
-
- expect(newBalances[validTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[validTakerAddress][defaultMakerAssetAddress].plus(makerAssetFillAmount.times(2)),
- );
- expect(newBalances[validTakerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[validTakerAddress][zrxToken.address].minus(takerFeePaid),
- );
- // Fee recipient
- expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[feeRecipientAddress][zrxToken.address].plus(makerFeePaid.times(2).plus(takerFeePaid)),
- );
- });
- it('should revert if one maker does not meet the balance threshold', async () => {
- // Create order set with one non-valid maker address
- const takerAssetFillAmounts = [takerAssetFillAmount, takerAssetFillAmount];
- const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({
- makerAddress: invalidAddress,
- });
- const orders = [validSignedOrder, signedOrderWithBadMakerAddress];
- // Execute transaction
- return expectTransactionFailedAsync(
- erc721TakerBalanceThresholdWrapper.batchFillOrdersAsync(orders, validTakerAddress, {
- takerAssetFillAmounts,
- }),
- RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold,
- );
- });
- it('should revert if taker does not meet the balance threshold', async () => {
- const orders = [validSignedOrder, validSignedOrder2];
- const takerAssetFillAmounts = [takerAssetFillAmount, takerAssetFillAmount];
- return expectTransactionFailedAsync(
- erc721NonValidBalanceThresholdWrapper.batchFillOrdersAsync(orders, invalidAddress, {
- takerAssetFillAmounts,
- }),
- RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold,
- );
- });
- });
-
- describe('batchFillOrdersNoThrow', () => {
- beforeEach(async () => {
- erc20Balances = await erc20Wrapper.getBalancesAsync();
- validSignedOrder = await orderFactory.newSignedOrderAsync();
- validSignedOrder2 = await orderFactory2.newSignedOrderAsync();
- });
- it('should transfer the correct amounts and validate both makers/taker when both maker and taker meet the balance threshold', async () => {
- // Execute a valid fill
- const orders = [validSignedOrder, validSignedOrder2];
- const takerAssetFillAmounts = [takerAssetFillAmount, takerAssetFillAmount];
- const txReceipt = await erc721TakerBalanceThresholdWrapper.batchFillOrdersNoThrowAsync(
- orders,
- validTakerAddress,
- {
- takerAssetFillAmounts,
- // HACK(albrow): We need to hardcode the gas estimate here because
- // the Geth gas estimator doesn't work with the way we use
- // delegatecall and swallow errors.
- gas: 600000,
- },
- );
- // Assert validated addresses
- const expectedValidatedAddresseses = [
- validSignedOrder.makerAddress,
- validSignedOrder2.makerAddress,
- validTakerAddress,
- ];
- await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
- // Check balances
- const newBalances = await erc20Wrapper.getBalancesAsync();
- const cumulativeTakerAssetFillAmount = takerAssetFillAmount.times(2);
- const makerAssetFillAmount = takerAssetFillAmount
- .times(validSignedOrder.makerAssetAmount)
- .dividedToIntegerBy(validSignedOrder.takerAssetAmount);
- const makerFeePaid = validSignedOrder.makerFee
- .times(makerAssetFillAmount)
- .dividedToIntegerBy(validSignedOrder.makerAssetAmount);
- const takerFeePaid = validSignedOrder.takerFee
- .times(makerAssetFillAmount)
- .dividedToIntegerBy(validSignedOrder.makerAssetAmount)
- .times(2);
- // Maker #1
- expect(newBalances[validMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[validMakerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount),
- );
- expect(newBalances[validMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[validMakerAddress][defaultTakerAssetAddress].plus(takerAssetFillAmount),
- );
- expect(newBalances[validMakerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[validMakerAddress][zrxToken.address].minus(makerFeePaid),
- );
- // Maker #2
- expect(newBalances[validMakerAddress2][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[validMakerAddress2][defaultMakerAssetAddress].minus(makerAssetFillAmount),
- );
- expect(newBalances[validMakerAddress2][defaultTakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[validMakerAddress2][defaultTakerAssetAddress].plus(takerAssetFillAmount),
- );
- expect(newBalances[validMakerAddress2][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[validMakerAddress2][zrxToken.address].minus(makerFeePaid),
- );
- // Taker
- expect(newBalances[validTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[validTakerAddress][defaultTakerAssetAddress].minus(cumulativeTakerAssetFillAmount),
- );
-
- expect(newBalances[validTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[validTakerAddress][defaultMakerAssetAddress].plus(makerAssetFillAmount.times(2)),
- );
- expect(newBalances[validTakerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[validTakerAddress][zrxToken.address].minus(takerFeePaid),
- );
- // Fee recipient
- expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[feeRecipientAddress][zrxToken.address].plus(makerFeePaid.times(2).plus(takerFeePaid)),
- );
- });
- it('should revert if one maker does not meet the balance threshold', async () => {
- // Create order set with one non-valid maker address
- const takerAssetFillAmounts = [takerAssetFillAmount, takerAssetFillAmount];
- const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({
- makerAddress: invalidAddress,
- });
- const orders = [validSignedOrder, signedOrderWithBadMakerAddress];
- // Execute transaction
- return expectTransactionFailedAsync(
- erc721TakerBalanceThresholdWrapper.batchFillOrdersNoThrowAsync(orders, validTakerAddress, {
- takerAssetFillAmounts,
- }),
- RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold,
- );
- });
- it('should revert if taker does not meet the balance threshold', async () => {
- const orders = [validSignedOrder, validSignedOrder2];
- const takerAssetFillAmounts = [takerAssetFillAmount, takerAssetFillAmount];
- return expectTransactionFailedAsync(
- erc721NonValidBalanceThresholdWrapper.batchFillOrdersNoThrowAsync(orders, invalidAddress, {
- takerAssetFillAmounts,
- }),
- RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold,
- );
- });
- });
-
- describe('batchFillOrKillOrders', () => {
- beforeEach(async () => {
- erc20Balances = await erc20Wrapper.getBalancesAsync();
- validSignedOrder = await orderFactory.newSignedOrderAsync();
- validSignedOrder2 = await orderFactory2.newSignedOrderAsync();
- });
- it('should transfer the correct amounts and validate both makers/taker when both makers and taker meet the balance threshold', async () => {
- // Execute a valid fill
- const orders = [validSignedOrder, validSignedOrder2];
- const takerAssetFillAmounts = [takerAssetFillAmount, takerAssetFillAmount];
- const txReceipt = await erc721TakerBalanceThresholdWrapper.batchFillOrKillOrdersAsync(
- orders,
- validTakerAddress,
- { takerAssetFillAmounts },
- );
- // Assert validated addresses
- const expectedValidatedAddresseses = [
- validSignedOrder.makerAddress,
- validSignedOrder2.makerAddress,
- validTakerAddress,
- ];
- await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
- // Check balances
- const newBalances = await erc20Wrapper.getBalancesAsync();
- const cumulativeTakerAssetFillAmount = takerAssetFillAmount.times(2);
- const makerAssetFillAmount = takerAssetFillAmount
- .times(validSignedOrder.makerAssetAmount)
- .dividedToIntegerBy(validSignedOrder.takerAssetAmount);
- const makerFeePaid = validSignedOrder.makerFee
- .times(makerAssetFillAmount)
- .dividedToIntegerBy(validSignedOrder.makerAssetAmount);
- const takerFeePaid = validSignedOrder.takerFee
- .times(makerAssetFillAmount)
- .dividedToIntegerBy(validSignedOrder.makerAssetAmount)
- .times(2);
- // Maker #1
- expect(newBalances[validMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[validMakerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount),
- );
- expect(newBalances[validMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[validMakerAddress][defaultTakerAssetAddress].plus(takerAssetFillAmount),
- );
- expect(newBalances[validMakerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[validMakerAddress][zrxToken.address].minus(makerFeePaid),
- );
- // Maker #2
- expect(newBalances[validMakerAddress2][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[validMakerAddress2][defaultMakerAssetAddress].minus(makerAssetFillAmount),
- );
- expect(newBalances[validMakerAddress2][defaultTakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[validMakerAddress2][defaultTakerAssetAddress].plus(takerAssetFillAmount),
- );
- expect(newBalances[validMakerAddress2][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[validMakerAddress2][zrxToken.address].minus(makerFeePaid),
- );
- // Taker
- expect(newBalances[validTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[validTakerAddress][defaultTakerAssetAddress].minus(cumulativeTakerAssetFillAmount),
- );
-
- expect(newBalances[validTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[validTakerAddress][defaultMakerAssetAddress].plus(makerAssetFillAmount.times(2)),
- );
- expect(newBalances[validTakerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[validTakerAddress][zrxToken.address].minus(takerFeePaid),
- );
- // Fee recipient
- expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[feeRecipientAddress][zrxToken.address].plus(makerFeePaid.times(2).plus(takerFeePaid)),
- );
- });
- it('should revert if one maker does not meet the balance threshold', async () => {
- // Create order set with one non-valid maker address
- const takerAssetFillAmounts = [takerAssetFillAmount, takerAssetFillAmount];
- const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({
- makerAddress: invalidAddress,
- });
- const orders = [validSignedOrder, signedOrderWithBadMakerAddress];
- // Execute transaction
- return expectTransactionFailedAsync(
- erc721TakerBalanceThresholdWrapper.batchFillOrKillOrdersAsync(orders, validTakerAddress, {
- takerAssetFillAmounts,
- }),
- RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold,
- );
- });
- it('should revert if taker does not meet the balance threshold', async () => {
- const orders = [validSignedOrder, validSignedOrder2];
- const takerAssetFillAmounts = [takerAssetFillAmount, takerAssetFillAmount];
- return expectTransactionFailedAsync(
- erc721NonValidBalanceThresholdWrapper.batchFillOrKillOrdersAsync(orders, invalidAddress, {
- takerAssetFillAmounts,
- }),
- RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold,
- );
- });
- it('should revert if one takerAssetFillAmount is not fully filled', async () => {
- const tooBigTakerAssetFillAmount = validSignedOrder.takerAssetAmount.times(2);
- const orders = [validSignedOrder, validSignedOrder2];
- const takerAssetFillAmounts = [takerAssetFillAmount, tooBigTakerAssetFillAmount];
- return expectTransactionFailedAsync(
- erc721TakerBalanceThresholdWrapper.batchFillOrKillOrdersAsync(orders, validTakerAddress, {
- takerAssetFillAmounts,
- }),
- RevertReason.FailedExecution,
- );
- });
- });
-
- describe('fillOrder', () => {
- beforeEach(async () => {
- erc20Balances = await erc20Wrapper.getBalancesAsync();
- validSignedOrder = await orderFactory.newSignedOrderAsync();
- });
- it('should transfer the correct amounts and validate both maker/taker when both maker and taker meet the balance threshold', async () => {
- // Execute a valid fill
- const txReceipt = await erc721TakerBalanceThresholdWrapper.fillOrderAsync(
- validSignedOrder,
- validTakerAddress,
- { takerAssetFillAmount },
- );
- // Assert validated addresses
- const expectedValidatedAddresseses = [validSignedOrder.makerAddress, validTakerAddress];
- await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
- // Check balances
- const newBalances = await erc20Wrapper.getBalancesAsync();
- const makerAssetFillAmount = takerAssetFillAmount
- .times(validSignedOrder.makerAssetAmount)
- .dividedToIntegerBy(validSignedOrder.takerAssetAmount);
- const makerFeePaid = validSignedOrder.makerFee
- .times(makerAssetFillAmount)
- .dividedToIntegerBy(validSignedOrder.makerAssetAmount);
- const takerFeePaid = validSignedOrder.takerFee
- .times(makerAssetFillAmount)
- .dividedToIntegerBy(validSignedOrder.makerAssetAmount);
- expect(newBalances[validMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[validMakerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount),
- );
- expect(newBalances[validMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[validMakerAddress][defaultTakerAssetAddress].plus(takerAssetFillAmount),
- );
- expect(newBalances[validMakerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[validMakerAddress][zrxToken.address].minus(makerFeePaid),
- );
- expect(newBalances[validTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[validTakerAddress][defaultTakerAssetAddress].minus(takerAssetFillAmount),
- );
- expect(newBalances[validTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[validTakerAddress][defaultMakerAssetAddress].plus(makerAssetFillAmount),
- );
- expect(newBalances[validTakerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[validTakerAddress][zrxToken.address].minus(takerFeePaid),
- );
- expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[feeRecipientAddress][zrxToken.address].plus(makerFeePaid.plus(takerFeePaid)),
- );
- });
- it('should revert if maker does not meet the balance threshold', async () => {
- // Create signed order with non-valid maker address
- const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({
- senderAddress: erc721BalanceThresholdFilterInstance.address,
- makerAddress: invalidAddress,
- });
- // Execute transaction
- return expectTransactionFailedAsync(
- erc721TakerBalanceThresholdWrapper.fillOrderAsync(signedOrderWithBadMakerAddress, validTakerAddress, {
- takerAssetFillAmount,
- }),
- RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold,
- );
- });
- it('should revert if taker does not meet the balance threshold', async () => {
- return expectTransactionFailedAsync(
- erc721NonValidBalanceThresholdWrapper.fillOrderAsync(validSignedOrder, invalidAddress, {
- takerAssetFillAmount,
- }),
- RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold,
- );
- });
- });
-
- describe('fillOrderNoThrow', () => {
- beforeEach(async () => {
- erc20Balances = await erc20Wrapper.getBalancesAsync();
- validSignedOrder = await orderFactory.newSignedOrderAsync();
- });
- it('should transfer the correct amounts and validate both maker/taker when both maker and taker meet the balance threshold', async () => {
- // Execute a valid fill
- const txReceipt = await erc721TakerBalanceThresholdWrapper.fillOrderNoThrowAsync(
- validSignedOrder,
- validTakerAddress,
- {
- takerAssetFillAmount,
- // HACK(albrow): We need to hardcode the gas estimate here because
- // the Geth gas estimator doesn't work with the way we use
- // delegatecall and swallow errors.
- gas: 600000,
- },
- );
- // Assert validated addresses
- const expectedValidatedAddresseses = [validSignedOrder.makerAddress, validTakerAddress];
- await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
- // Check balances
- const newBalances = await erc20Wrapper.getBalancesAsync();
- const makerAssetFillAmount = takerAssetFillAmount
- .times(validSignedOrder.makerAssetAmount)
- .dividedToIntegerBy(validSignedOrder.takerAssetAmount);
- const makerFeePaid = validSignedOrder.makerFee
- .times(makerAssetFillAmount)
- .dividedToIntegerBy(validSignedOrder.makerAssetAmount);
- const takerFeePaid = validSignedOrder.takerFee
- .times(makerAssetFillAmount)
- .dividedToIntegerBy(validSignedOrder.makerAssetAmount);
- expect(newBalances[validMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[validMakerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount),
- );
- expect(newBalances[validMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[validMakerAddress][defaultTakerAssetAddress].plus(takerAssetFillAmount),
- );
- expect(newBalances[validMakerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[validMakerAddress][zrxToken.address].minus(makerFeePaid),
- );
- expect(newBalances[validTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[validTakerAddress][defaultTakerAssetAddress].minus(takerAssetFillAmount),
- );
- expect(newBalances[validTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[validTakerAddress][defaultMakerAssetAddress].plus(makerAssetFillAmount),
- );
- expect(newBalances[validTakerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[validTakerAddress][zrxToken.address].minus(takerFeePaid),
- );
- expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[feeRecipientAddress][zrxToken.address].plus(makerFeePaid.plus(takerFeePaid)),
- );
- });
- it('should revert if maker does not meet the balance threshold', async () => {
- // Create signed order with non-valid maker address
- const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({
- senderAddress: erc721BalanceThresholdFilterInstance.address,
- makerAddress: invalidAddress,
- });
- // Execute transaction
- return expectTransactionFailedAsync(
- erc721TakerBalanceThresholdWrapper.fillOrderNoThrowAsync(
- signedOrderWithBadMakerAddress,
- validTakerAddress,
- { takerAssetFillAmount },
- ),
- RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold,
- );
- });
- it('should revert if taker does not meet the balance threshold', async () => {
- return expectTransactionFailedAsync(
- erc721NonValidBalanceThresholdWrapper.fillOrderNoThrowAsync(validSignedOrder, invalidAddress, {
- takerAssetFillAmount,
- }),
- RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold,
- );
- });
- });
-
- describe('fillOrKillOrder', () => {
- beforeEach(async () => {
- erc20Balances = await erc20Wrapper.getBalancesAsync();
- validSignedOrder = await orderFactory.newSignedOrderAsync();
- });
- it('should transfer the correct amounts and validate both maker/taker when both maker and taker meet the balance threshold', async () => {
- // Execute a valid fill
- const takerAssetFillAmount_ = validSignedOrder.takerAssetAmount;
- const txReceipt = await erc721TakerBalanceThresholdWrapper.fillOrKillOrderAsync(
- validSignedOrder,
- validTakerAddress,
- { takerAssetFillAmount: takerAssetFillAmount_ },
- );
- // Assert validated addresses
- const expectedValidatedAddresseses = [validSignedOrder.makerAddress, validTakerAddress];
- await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
- // Check balances
- const newBalances = await erc20Wrapper.getBalancesAsync();
- const makerAssetFillAmount = takerAssetFillAmount_
- .times(validSignedOrder.makerAssetAmount)
- .dividedToIntegerBy(validSignedOrder.takerAssetAmount);
- const makerFeePaid = validSignedOrder.makerFee
- .times(makerAssetFillAmount)
- .dividedToIntegerBy(validSignedOrder.makerAssetAmount);
- const takerFeePaid = validSignedOrder.takerFee
- .times(makerAssetFillAmount)
- .dividedToIntegerBy(validSignedOrder.makerAssetAmount);
- expect(newBalances[validMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[validMakerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount),
- );
- expect(newBalances[validMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[validMakerAddress][defaultTakerAssetAddress].plus(takerAssetFillAmount_),
- );
- expect(newBalances[validMakerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[validMakerAddress][zrxToken.address].minus(makerFeePaid),
- );
- expect(newBalances[validTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[validTakerAddress][defaultTakerAssetAddress].minus(takerAssetFillAmount_),
- );
- expect(newBalances[validTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[validTakerAddress][defaultMakerAssetAddress].plus(makerAssetFillAmount),
- );
- expect(newBalances[validTakerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[validTakerAddress][zrxToken.address].minus(takerFeePaid),
- );
- expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[feeRecipientAddress][zrxToken.address].plus(makerFeePaid.plus(takerFeePaid)),
- );
- });
- it('should revert if maker does not meet the balance threshold', async () => {
- // Create signed order with non-valid maker address
- const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({
- senderAddress: erc721BalanceThresholdFilterInstance.address,
- makerAddress: invalidAddress,
- });
- // Execute transaction
- return expectTransactionFailedAsync(
- erc721TakerBalanceThresholdWrapper.fillOrKillOrderAsync(
- signedOrderWithBadMakerAddress,
- validTakerAddress,
- { takerAssetFillAmount },
- ),
- RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold,
- );
- });
- it('should revert if taker does not meet the balance threshold', async () => {
- return expectTransactionFailedAsync(
- erc721NonValidBalanceThresholdWrapper.fillOrKillOrderAsync(validSignedOrder, invalidAddress, {
- takerAssetFillAmount,
- }),
- RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold,
- );
- });
- it('should revert if takerAssetFillAmount is not fully filled', async () => {
- const tooBigTakerAssetFillAmount = validSignedOrder.takerAssetAmount.times(2);
- return expectTransactionFailedAsync(
- erc721TakerBalanceThresholdWrapper.fillOrKillOrderAsync(validSignedOrder, validTakerAddress, {
- takerAssetFillAmount: tooBigTakerAssetFillAmount,
- }),
- RevertReason.FailedExecution,
- );
- });
- });
-
- describe('marketSellOrders', () => {
- beforeEach(async () => {
- erc20Balances = await erc20Wrapper.getBalancesAsync();
- validSignedOrder = await orderFactory.newSignedOrderAsync();
- validSignedOrder2 = await orderFactory2.newSignedOrderAsync();
- });
- it('should transfer the correct amounts and validate both makers/taker when both makers and taker meet the balance threshold', async () => {
- // Execute a valid fill
- const orders = [validSignedOrder, validSignedOrder2];
- const cumulativeTakerAssetFillAmount = validSignedOrder.takerAssetAmount.plus(takerAssetFillAmount);
- const txReceipt = await erc721TakerBalanceThresholdWrapper.marketSellOrdersAsync(
- orders,
- validTakerAddress,
- { takerAssetFillAmount: cumulativeTakerAssetFillAmount },
- );
- // Assert validated addresses
- const expectedValidatedAddresseses = [
- validSignedOrder.makerAddress,
- validSignedOrder2.makerAddress,
- validTakerAddress,
- ];
- await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
- // Check balances
- const newBalances = await erc20Wrapper.getBalancesAsync();
- const makerAssetFillAmount2 = takerAssetFillAmount
- .times(validSignedOrder.makerAssetAmount)
- .dividedToIntegerBy(validSignedOrder.takerAssetAmount);
- const makerFeePaid2 = validSignedOrder2.makerFee
- .times(makerAssetFillAmount2)
- .dividedToIntegerBy(validSignedOrder2.makerAssetAmount);
- const takerFeePaid2 = validSignedOrder2.takerFee
- .times(makerAssetFillAmount2)
- .dividedToIntegerBy(validSignedOrder2.makerAssetAmount);
- const takerFeePaid = validSignedOrder.takerFee.plus(takerFeePaid2);
- const cumulativeMakerAssetFillAmount = validSignedOrder.makerAssetAmount.plus(makerAssetFillAmount2);
- // Maker #1
- expect(newBalances[validMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[validMakerAddress][defaultMakerAssetAddress].minus(validSignedOrder.makerAssetAmount),
- );
- expect(newBalances[validMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[validMakerAddress][defaultTakerAssetAddress].plus(validSignedOrder.takerAssetAmount),
- );
- expect(newBalances[validMakerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[validMakerAddress][zrxToken.address].minus(validSignedOrder.makerFee),
- );
- // Maker #2
- expect(newBalances[validMakerAddress2][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[validMakerAddress2][defaultMakerAssetAddress].minus(makerAssetFillAmount2),
- );
- expect(newBalances[validMakerAddress2][defaultTakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[validMakerAddress2][defaultTakerAssetAddress].plus(takerAssetFillAmount),
- );
- expect(newBalances[validMakerAddress2][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[validMakerAddress2][zrxToken.address].minus(makerFeePaid2),
- );
- // Taker
- expect(newBalances[validTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[validTakerAddress][defaultTakerAssetAddress].minus(cumulativeTakerAssetFillAmount),
- );
- expect(newBalances[validTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[validTakerAddress][defaultMakerAssetAddress].plus(cumulativeMakerAssetFillAmount),
- );
- expect(newBalances[validTakerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[validTakerAddress][zrxToken.address].minus(takerFeePaid),
- );
- // Fee recipient
- expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[feeRecipientAddress][zrxToken.address]
- .plus(validSignedOrder.makerFee)
- .plus(makerFeePaid2)
- .plus(takerFeePaid),
- );
- });
- it('should revert if one maker does not meet the balance threshold', async () => {
- // Create order set with one non-valid maker address
- const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({
- makerAddress: invalidAddress,
- });
- const orders = [validSignedOrder, signedOrderWithBadMakerAddress];
- // Execute transaction
- return expectTransactionFailedAsync(
- erc721TakerBalanceThresholdWrapper.marketSellOrdersAsync(orders, validTakerAddress, {
- takerAssetFillAmount,
- }),
- RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold,
- );
- });
- it('should revert if taker does not meet the balance threshold', async () => {
- const orders = [validSignedOrder, validSignedOrder2];
- return expectTransactionFailedAsync(
- erc721NonValidBalanceThresholdWrapper.marketSellOrdersAsync(orders, invalidAddress, {
- takerAssetFillAmount,
- }),
- RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold,
- );
- });
- });
-
- describe('marketSellOrdersNoThrow', () => {
- beforeEach(async () => {
- erc20Balances = await erc20Wrapper.getBalancesAsync();
- validSignedOrder = await orderFactory.newSignedOrderAsync();
- validSignedOrder2 = await orderFactory2.newSignedOrderAsync();
- });
- it('should transfer the correct amounts and validate both makers/taker when both makers and taker meet the balance threshold', async () => {
- // Execute a valid fill
- const orders = [validSignedOrder, validSignedOrder2];
- const cumulativeTakerAssetFillAmount = validSignedOrder.takerAssetAmount.plus(takerAssetFillAmount);
- const txReceipt = await erc721TakerBalanceThresholdWrapper.marketSellOrdersNoThrowAsync(
- orders,
- validTakerAddress,
- {
- takerAssetFillAmount: cumulativeTakerAssetFillAmount,
- // HACK(albrow): We need to hardcode the gas estimate here because
- // the Geth gas estimator doesn't work with the way we use
- // delegatecall and swallow errors.
- gas: 600000,
- },
- );
- // Assert validated addresses
- const expectedValidatedAddresseses = [
- validSignedOrder.makerAddress,
- validSignedOrder2.makerAddress,
- validTakerAddress,
- ];
- await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
- // Check balances
- const newBalances = await erc20Wrapper.getBalancesAsync();
- const makerAssetFillAmount2 = takerAssetFillAmount
- .times(validSignedOrder.makerAssetAmount)
- .dividedToIntegerBy(validSignedOrder.takerAssetAmount);
- const makerFeePaid2 = validSignedOrder2.makerFee
- .times(makerAssetFillAmount2)
- .dividedToIntegerBy(validSignedOrder2.makerAssetAmount);
- const takerFeePaid2 = validSignedOrder2.takerFee
- .times(makerAssetFillAmount2)
- .dividedToIntegerBy(validSignedOrder2.makerAssetAmount);
- const takerFeePaid = validSignedOrder.takerFee.plus(takerFeePaid2);
- const cumulativeMakerAssetFillAmount = validSignedOrder.makerAssetAmount.plus(makerAssetFillAmount2);
- // Maker #1
- expect(newBalances[validMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[validMakerAddress][defaultMakerAssetAddress].minus(validSignedOrder.makerAssetAmount),
- );
- expect(newBalances[validMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[validMakerAddress][defaultTakerAssetAddress].plus(validSignedOrder.takerAssetAmount),
- );
- expect(newBalances[validMakerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[validMakerAddress][zrxToken.address].minus(validSignedOrder.makerFee),
- );
- // Maker #2
- expect(newBalances[validMakerAddress2][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[validMakerAddress2][defaultMakerAssetAddress].minus(makerAssetFillAmount2),
- );
- expect(newBalances[validMakerAddress2][defaultTakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[validMakerAddress2][defaultTakerAssetAddress].plus(takerAssetFillAmount),
- );
- expect(newBalances[validMakerAddress2][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[validMakerAddress2][zrxToken.address].minus(makerFeePaid2),
- );
- // Taker
- expect(newBalances[validTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[validTakerAddress][defaultTakerAssetAddress].minus(cumulativeTakerAssetFillAmount),
- );
- expect(newBalances[validTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[validTakerAddress][defaultMakerAssetAddress].plus(cumulativeMakerAssetFillAmount),
- );
- expect(newBalances[validTakerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[validTakerAddress][zrxToken.address].minus(takerFeePaid),
- );
- // Fee recipient
- expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[feeRecipientAddress][zrxToken.address]
- .plus(validSignedOrder.makerFee)
- .plus(makerFeePaid2)
- .plus(takerFeePaid),
- );
- });
- it('should revert if one maker does not meet the balance threshold', async () => {
- // Create order set with one non-valid maker address
- const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({
- makerAddress: invalidAddress,
- });
- const orders = [validSignedOrder, signedOrderWithBadMakerAddress];
- // Execute transaction
- return expectTransactionFailedAsync(
- erc721TakerBalanceThresholdWrapper.marketSellOrdersNoThrowAsync(orders, validTakerAddress, {
- takerAssetFillAmount,
- }),
- RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold,
- );
- });
- it('should revert if taker does not meet the balance threshold', async () => {
- const orders = [validSignedOrder, validSignedOrder2];
- return expectTransactionFailedAsync(
- erc721NonValidBalanceThresholdWrapper.marketSellOrdersNoThrowAsync(orders, invalidAddress, {
- takerAssetFillAmount,
- }),
- RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold,
- );
- });
- });
-
- describe('marketBuyOrders', () => {
- beforeEach(async () => {
- erc20Balances = await erc20Wrapper.getBalancesAsync();
- validSignedOrder = await orderFactory.newSignedOrderAsync();
- validSignedOrder2 = await orderFactory2.newSignedOrderAsync();
- });
- it('should transfer the correct amounts and validate both makers/taker when both makers and taker meet the balance threshold', async () => {
- // Execute a valid fill
- const orders = [validSignedOrder, validSignedOrder2];
- const cumulativeTakerAssetFillAmount = validSignedOrder.takerAssetAmount.plus(takerAssetFillAmount);
- const makerAssetFillAmount2 = takerAssetFillAmount
- .times(validSignedOrder.makerAssetAmount)
- .dividedToIntegerBy(validSignedOrder.takerAssetAmount);
- const cumulativeMakerAssetFillAmount = validSignedOrder.makerAssetAmount.plus(makerAssetFillAmount2);
- const txReceipt = await erc721TakerBalanceThresholdWrapper.marketBuyOrdersAsync(orders, validTakerAddress, {
- makerAssetFillAmount: cumulativeMakerAssetFillAmount,
- });
- // Assert validated addresses
- const expectedValidatedAddresseses = [
- validSignedOrder.makerAddress,
- validSignedOrder2.makerAddress,
- validTakerAddress,
- ];
- await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
- // Check balances
- const newBalances = await erc20Wrapper.getBalancesAsync();
- const makerFeePaid2 = validSignedOrder2.makerFee
- .times(makerAssetFillAmount2)
- .dividedToIntegerBy(validSignedOrder2.makerAssetAmount);
- const takerFeePaid2 = validSignedOrder2.takerFee
- .times(makerAssetFillAmount2)
- .dividedToIntegerBy(validSignedOrder2.makerAssetAmount);
- const takerFeePaid = validSignedOrder.takerFee.plus(takerFeePaid2);
- // Maker #1
- expect(newBalances[validMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[validMakerAddress][defaultMakerAssetAddress].minus(validSignedOrder.makerAssetAmount),
- );
- expect(newBalances[validMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[validMakerAddress][defaultTakerAssetAddress].plus(validSignedOrder.takerAssetAmount),
- );
- expect(newBalances[validMakerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[validMakerAddress][zrxToken.address].minus(validSignedOrder.makerFee),
- );
- // Maker #2
- expect(newBalances[validMakerAddress2][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[validMakerAddress2][defaultMakerAssetAddress].minus(makerAssetFillAmount2),
- );
- expect(newBalances[validMakerAddress2][defaultTakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[validMakerAddress2][defaultTakerAssetAddress].plus(takerAssetFillAmount),
- );
- expect(newBalances[validMakerAddress2][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[validMakerAddress2][zrxToken.address].minus(makerFeePaid2),
- );
- // Taker
- expect(newBalances[validTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[validTakerAddress][defaultTakerAssetAddress].minus(cumulativeTakerAssetFillAmount),
- );
- expect(newBalances[validTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[validTakerAddress][defaultMakerAssetAddress].plus(cumulativeMakerAssetFillAmount),
- );
- expect(newBalances[validTakerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[validTakerAddress][zrxToken.address].minus(takerFeePaid),
- );
- // Fee recipient
- expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[feeRecipientAddress][zrxToken.address]
- .plus(validSignedOrder.makerFee)
- .plus(makerFeePaid2)
- .plus(takerFeePaid),
- );
- });
- it('should revert if one maker does not meet the balance threshold', async () => {
- // Create order set with one non-valid maker address
- const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({
- makerAddress: invalidAddress,
- });
- const orders = [validSignedOrder, signedOrderWithBadMakerAddress];
- // Execute transaction
- const dummyMakerAssetFillAmount = new BigNumber(0);
- return expectTransactionFailedAsync(
- erc721TakerBalanceThresholdWrapper.marketBuyOrdersAsync(orders, validTakerAddress, {
- makerAssetFillAmount: dummyMakerAssetFillAmount,
- }),
- RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold,
- );
- });
- it('should revert if taker does not meet the balance threshold', async () => {
- const orders = [validSignedOrder, validSignedOrder2];
- const dummyMakerAssetFillAmount = new BigNumber(0);
- return expectTransactionFailedAsync(
- erc721NonValidBalanceThresholdWrapper.marketBuyOrdersAsync(orders, invalidAddress, {
- makerAssetFillAmount: dummyMakerAssetFillAmount,
- }),
- RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold,
- );
- });
- });
-
- describe('marketBuyOrdersNoThrowAsync', () => {
- beforeEach(async () => {
- erc20Balances = await erc20Wrapper.getBalancesAsync();
- validSignedOrder = await orderFactory.newSignedOrderAsync();
- validSignedOrder2 = await orderFactory2.newSignedOrderAsync();
- });
- it('should transfer the correct amounts and validate both makers/taker when both makers and taker meet the balance threshold', async () => {
- // Execute a valid fill
- const orders = [validSignedOrder, validSignedOrder2];
- const cumulativeTakerAssetFillAmount = validSignedOrder.takerAssetAmount.plus(takerAssetFillAmount);
- const makerAssetFillAmount2 = takerAssetFillAmount
- .times(validSignedOrder.makerAssetAmount)
- .dividedToIntegerBy(validSignedOrder.takerAssetAmount);
- const cumulativeMakerAssetFillAmount = validSignedOrder.makerAssetAmount.plus(makerAssetFillAmount2);
- const txReceipt = await erc721TakerBalanceThresholdWrapper.marketBuyOrdersNoThrowAsync(
- orders,
- validTakerAddress,
- {
- makerAssetFillAmount: cumulativeMakerAssetFillAmount,
- // HACK(albrow): We need to hardcode the gas estimate here because
- // the Geth gas estimator doesn't work with the way we use
- // delegatecall and swallow errors.
- gas: 600000,
- },
- );
- // Assert validated addresses
- const expectedValidatedAddresseses = [
- validSignedOrder.makerAddress,
- validSignedOrder2.makerAddress,
- validTakerAddress,
- ];
- await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
- // Check balances
- const newBalances = await erc20Wrapper.getBalancesAsync();
- const makerFeePaid2 = validSignedOrder2.makerFee
- .times(makerAssetFillAmount2)
- .dividedToIntegerBy(validSignedOrder2.makerAssetAmount);
- const takerFeePaid2 = validSignedOrder2.takerFee
- .times(makerAssetFillAmount2)
- .dividedToIntegerBy(validSignedOrder2.makerAssetAmount);
- const takerFeePaid = validSignedOrder.takerFee.plus(takerFeePaid2);
- // Maker #1
- expect(newBalances[validMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[validMakerAddress][defaultMakerAssetAddress].minus(validSignedOrder.makerAssetAmount),
- );
- expect(newBalances[validMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[validMakerAddress][defaultTakerAssetAddress].plus(validSignedOrder.takerAssetAmount),
- );
- expect(newBalances[validMakerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[validMakerAddress][zrxToken.address].minus(validSignedOrder.makerFee),
- );
- // Maker #2
- expect(newBalances[validMakerAddress2][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[validMakerAddress2][defaultMakerAssetAddress].minus(makerAssetFillAmount2),
- );
- expect(newBalances[validMakerAddress2][defaultTakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[validMakerAddress2][defaultTakerAssetAddress].plus(takerAssetFillAmount),
- );
- expect(newBalances[validMakerAddress2][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[validMakerAddress2][zrxToken.address].minus(makerFeePaid2),
- );
- // Taker
- expect(newBalances[validTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[validTakerAddress][defaultTakerAssetAddress].minus(cumulativeTakerAssetFillAmount),
- );
- expect(newBalances[validTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[validTakerAddress][defaultMakerAssetAddress].plus(cumulativeMakerAssetFillAmount),
- );
- expect(newBalances[validTakerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[validTakerAddress][zrxToken.address].minus(takerFeePaid),
- );
- // Fee recipient
- expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[feeRecipientAddress][zrxToken.address]
- .plus(validSignedOrder.makerFee)
- .plus(makerFeePaid2)
- .plus(takerFeePaid),
- );
- });
- it('should revert if one maker does not meet the balance threshold', async () => {
- // Create order set with one non-valid maker address
- const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({
- makerAddress: invalidAddress,
- });
- const orders = [validSignedOrder, signedOrderWithBadMakerAddress];
- // Execute transaction
- const dummyMakerAssetFillAmount = new BigNumber(0);
- return expectTransactionFailedAsync(
- erc721TakerBalanceThresholdWrapper.marketBuyOrdersNoThrowAsync(orders, validTakerAddress, {
- makerAssetFillAmount: dummyMakerAssetFillAmount,
- }),
- RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold,
- );
- });
- it('should revert if taker does not meet the balance threshold', async () => {
- const orders = [validSignedOrder, validSignedOrder2];
- const dummyMakerAssetFillAmount = new BigNumber(0);
- return expectTransactionFailedAsync(
- erc721NonValidBalanceThresholdWrapper.marketBuyOrdersNoThrowAsync(orders, invalidAddress, {
- makerAssetFillAmount: dummyMakerAssetFillAmount,
- }),
- RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold,
- );
- });
- });
-
- describe('matchOrders', () => {
- beforeEach(async () => {
- erc20Balances = await erc20Wrapper.getBalancesAsync();
- validSignedOrder = await orderFactory.newSignedOrderAsync();
- validSignedOrder2 = await orderFactory2.newSignedOrderAsync();
- });
- it('Should transfer correct amounts when both makers and taker meet the balance threshold', async () => {
- // Test values/results taken from Match Orders test:
- // 'Should transfer correct amounts when right order is fully filled and values pass isRoundingErrorFloor but fail isRoundingErrorCeil'
- // Create orders to match
- const signedOrderLeft = await orderFactory.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(17), 0),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(98), 0),
- makerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 18),
- takerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 18),
- feeRecipientAddress,
- });
- const signedOrderRight = await orderFactory2.newSignedOrderAsync({
- makerAssetData: assetDataUtils.encodeERC20AssetData(defaultTakerAssetAddress),
- takerAssetData: assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress),
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(75), 0),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(13), 0),
- makerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 18),
- takerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 18),
- feeRecipientAddress,
- });
- // Compute expected transfer amounts
- const expectedTransferAmounts = {
- // Left Maker
- amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(13), 0),
- amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(75), 0),
- feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber('76.4705882352941176'), 16), // 76.47%
- // Right Maker
- amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(75), 0),
- amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(13), 0),
- feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Taker
- amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(0), 0),
- feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber('76.5306122448979591'), 16), // 76.53%
- feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- };
- const txReceipt = await erc721TakerBalanceThresholdWrapper.matchOrdersAsync(
- signedOrderLeft,
- signedOrderRight,
- validTakerAddress,
- );
- // Assert validated addresses
- const expectedValidatedAddresseses = [
- signedOrderLeft.makerAddress,
- signedOrderRight.makerAddress,
- validTakerAddress,
- ];
- await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
- // Check balances
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(
- newBalances[signedOrderLeft.makerAddress][defaultMakerAssetAddress],
- 'Checking left maker egress ERC20 account balance',
- ).to.be.bignumber.equal(
- erc20Balances[signedOrderLeft.makerAddress][defaultMakerAssetAddress].minus(
- expectedTransferAmounts.amountSoldByLeftMaker,
- ),
- );
- expect(
- newBalances[signedOrderRight.makerAddress][defaultTakerAssetAddress],
- 'Checking right maker ingress ERC20 account balance',
- ).to.be.bignumber.equal(
- erc20Balances[signedOrderRight.makerAddress][defaultTakerAssetAddress].minus(
- expectedTransferAmounts.amountSoldByRightMaker,
- ),
- );
- expect(
- newBalances[validTakerAddress][defaultMakerAssetAddress],
- 'Checking taker ingress ERC20 account balance',
- ).to.be.bignumber.equal(
- erc20Balances[validTakerAddress][defaultMakerAssetAddress].plus(
- expectedTransferAmounts.amountReceivedByTaker,
- ),
- );
- expect(
- newBalances[signedOrderLeft.makerAddress][defaultTakerAssetAddress],
- 'Checking left maker ingress ERC20 account balance',
- ).to.be.bignumber.equal(
- erc20Balances[signedOrderLeft.makerAddress][defaultTakerAssetAddress].plus(
- expectedTransferAmounts.amountBoughtByLeftMaker,
- ),
- );
- expect(
- newBalances[signedOrderRight.makerAddress][defaultMakerAssetAddress],
- 'Checking right maker egress ERC20 account balance',
- ).to.be.bignumber.equal(
- erc20Balances[signedOrderRight.makerAddress][defaultMakerAssetAddress].plus(
- expectedTransferAmounts.amountBoughtByRightMaker,
- ),
- );
- // Paid fees
- expect(
- newBalances[signedOrderLeft.makerAddress][zrxToken.address],
- 'Checking left maker egress ERC20 account fees',
- ).to.be.bignumber.equal(
- erc20Balances[signedOrderLeft.makerAddress][zrxToken.address].minus(
- expectedTransferAmounts.feePaidByLeftMaker,
- ),
- );
- expect(
- newBalances[signedOrderRight.makerAddress][zrxToken.address],
- 'Checking right maker egress ERC20 account fees',
- ).to.be.bignumber.equal(
- erc20Balances[signedOrderRight.makerAddress][zrxToken.address].minus(
- expectedTransferAmounts.feePaidByRightMaker,
- ),
- );
- expect(
- newBalances[validTakerAddress][zrxToken.address],
- 'Checking taker egress ERC20 account fees',
- ).to.be.bignumber.equal(
- erc20Balances[validTakerAddress][zrxToken.address]
- .minus(expectedTransferAmounts.feePaidByTakerLeft)
- .minus(expectedTransferAmounts.feePaidByTakerRight),
- );
- // Received fees
- expect(
- newBalances[signedOrderLeft.feeRecipientAddress][zrxToken.address],
- 'Checking left fee recipient ingress ERC20 account fees',
- ).to.be.bignumber.equal(
- erc20Balances[feeRecipientAddress][zrxToken.address]
- .plus(expectedTransferAmounts.feePaidByLeftMaker)
- .plus(expectedTransferAmounts.feePaidByRightMaker)
- .plus(expectedTransferAmounts.feePaidByTakerLeft)
- .plus(expectedTransferAmounts.feePaidByTakerRight),
- );
- });
- it('should revert if left maker does not meet the balance threshold', async () => {
- // Create signed order with non-valid maker address
- const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({
- senderAddress: erc721BalanceThresholdFilterInstance.address,
- makerAddress: invalidAddress,
- });
- // Execute transaction
- return expectTransactionFailedAsync(
- erc721TakerBalanceThresholdWrapper.matchOrdersAsync(
- validSignedOrder,
- signedOrderWithBadMakerAddress,
- validTakerAddress,
- ),
- RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold,
- );
- });
- it('should revert if right maker does not meet the balance threshold', async () => {
- // Create signed order with non-valid maker address
- const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({
- senderAddress: erc721BalanceThresholdFilterInstance.address,
- makerAddress: invalidAddress,
- });
- // Execute transaction
- return expectTransactionFailedAsync(
- erc721TakerBalanceThresholdWrapper.matchOrdersAsync(
- signedOrderWithBadMakerAddress,
- validSignedOrder,
- validTakerAddress,
- ),
- RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold,
- );
- });
- it('should revert if taker does not meet the balance threshold', async () => {
- return expectTransactionFailedAsync(
- erc721NonValidBalanceThresholdWrapper.matchOrdersAsync(
- validSignedOrder,
- validSignedOrder,
- invalidAddress,
- ),
- RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold,
- );
- });
- });
-
- describe('cancelOrder', () => {
- beforeEach(async () => {
- erc20Balances = await erc20Wrapper.getBalancesAsync();
- validSignedOrder = await orderFactory.newSignedOrderAsync();
- validSignedOrder2 = await orderFactory2.newSignedOrderAsync();
- });
- it('Should successfully cancel order if maker meets balance threshold', async () => {
- // Verify order is not cancelled
- const orderInfoBeforeCancelling = await erc721MakerBalanceThresholdWrapper.getOrderInfoAsync(
- validSignedOrder,
- );
- expect(orderInfoBeforeCancelling.orderStatus).to.be.equal(OrderStatus.Fillable);
- // Cancel
- const txReceipt = await erc721MakerBalanceThresholdWrapper.cancelOrderAsync(
- validSignedOrder,
- validSignedOrder.makerAddress,
- );
- // Assert validated addresses
- const expectedValidatedAddresseses: string[] = [];
- await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
- // Check that order was cancelled
- const orderInfoAfterCancelling = await erc721MakerBalanceThresholdWrapper.getOrderInfoAsync(
- validSignedOrder,
- );
- expect(orderInfoAfterCancelling.orderStatus).to.be.equal(OrderStatus.Cancelled);
- });
- it('Should successfully cancel order if maker does not meet balance threshold', async () => {
- // Create order where maker does not meet balance threshold
- const signedOrderWithBadMakerAddress = await invalidOrderFactory.newSignedOrderAsync({});
- // Verify order is not cancelled
- const orderInfoBeforeCancelling = await erc721NonValidBalanceThresholdWrapper.getOrderInfoAsync(
- signedOrderWithBadMakerAddress,
- );
- expect(orderInfoBeforeCancelling.orderStatus).to.be.equal(OrderStatus.Fillable);
- // Cancel
- const txReceipt = await erc721NonValidBalanceThresholdWrapper.cancelOrderAsync(
- signedOrderWithBadMakerAddress,
- signedOrderWithBadMakerAddress.makerAddress,
- );
- // Assert validated addresses
- const expectedValidatedAddresseses: string[] = [];
- await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
- // Check that order was cancelled
- const orderInfoAfterCancelling = await erc721MakerBalanceThresholdWrapper.getOrderInfoAsync(
- signedOrderWithBadMakerAddress,
- );
- expect(orderInfoAfterCancelling.orderStatus).to.be.equal(OrderStatus.Cancelled);
- });
- });
-
- describe('batchCancelOrders', () => {
- beforeEach(async () => {
- erc20Balances = await erc20Wrapper.getBalancesAsync();
- });
- it('Should successfully batch cancel orders if maker meets balance threshold', async () => {
- // Create orders to cancel
- const validSignedOrders = [
- await orderFactory.newSignedOrderAsync(),
- await orderFactory.newSignedOrderAsync(),
- await orderFactory.newSignedOrderAsync(),
- ];
- // Verify orders are not cancelled
- _.each(validSignedOrders, async signedOrder => {
- const orderInfoBeforeCancelling = await erc721MakerBalanceThresholdWrapper.getOrderInfoAsync(
- signedOrder,
- );
- return expect(orderInfoBeforeCancelling.orderStatus).to.be.equal(OrderStatus.Fillable);
- });
- // Cancel
- const txReceipt = await erc721MakerBalanceThresholdWrapper.batchCancelOrdersAsync(
- validSignedOrders,
- validSignedOrders[0].makerAddress,
- );
- // Assert validated addresses
- const expectedValidatedAddresseses: string[] = [];
- await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
- // Check that order was cancelled
- _.each(validSignedOrders, async signedOrder => {
- const orderInfoAfterCancelling = await erc721MakerBalanceThresholdWrapper.getOrderInfoAsync(
- signedOrder,
- );
- return expect(orderInfoAfterCancelling.orderStatus).to.be.equal(OrderStatus.Cancelled);
- });
- });
- it('Should successfully batch cancel order if maker does not meet balance threshold', async () => {
- // Create orders to cancel
- const invalidSignedOrders = [
- await invalidOrderFactory.newSignedOrderAsync(),
- await invalidOrderFactory.newSignedOrderAsync(),
- await invalidOrderFactory.newSignedOrderAsync(),
- ];
- // Verify orders are not cancelled
- _.each(invalidSignedOrders, async signedOrder => {
- const orderInfoBeforeCancelling = await erc721NonValidBalanceThresholdWrapper.getOrderInfoAsync(
- signedOrder,
- );
- return expect(orderInfoBeforeCancelling.orderStatus).to.be.equal(OrderStatus.Fillable);
- });
- // Cancel
- const txReceipt = await erc721NonValidBalanceThresholdWrapper.batchCancelOrdersAsync(
- invalidSignedOrders,
- invalidAddress,
- );
- // Assert validated addresses
- const expectedValidatedAddresseses: string[] = [];
- await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
- // Check that order was cancelled
- _.each(invalidSignedOrders, async signedOrder => {
- const orderInfoAfterCancelling = await erc721NonValidBalanceThresholdWrapper.getOrderInfoAsync(
- signedOrder,
- );
- return expect(orderInfoAfterCancelling.orderStatus).to.be.equal(OrderStatus.Cancelled);
- });
- });
- });
-
- describe('cancelOrdersUpTo', () => {
- beforeEach(async () => {
- erc20Balances = await erc20Wrapper.getBalancesAsync();
- });
- it('Should successfully batch cancel orders if maker meets balance threshold', async () => {
- // Create orders to cancel
- const validSignedOrders = [
- await orderFactory.newSignedOrderAsync({ salt: new BigNumber(0) }),
- await orderFactory.newSignedOrderAsync({ salt: new BigNumber(1) }),
- await orderFactory.newSignedOrderAsync({ salt: new BigNumber(2) }),
- ];
- // Verify orders are not cancelled
- _.each(validSignedOrders, async signedOrder => {
- const orderInfoBeforeCancelling = await erc721MakerBalanceThresholdWrapper.getOrderInfoAsync(
- signedOrder,
- );
- return expect(orderInfoBeforeCancelling.orderStatus).to.be.equal(OrderStatus.Fillable);
- });
- // Cancel
- const cancelOrdersUpToThisSalt = new BigNumber(1);
- const txReceipt = await erc721MakerBalanceThresholdWrapper.cancelOrdersUpToAsync(
- cancelOrdersUpToThisSalt,
- validSignedOrders[0].makerAddress,
- );
- // Assert validated addresses
- const expectedValidatedAddresseses: string[] = [];
- await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
- // Check that order was cancelled
- _.each(validSignedOrders, async (signedOrder, salt: number) => {
- const orderInfoAfterCancelling = await erc721MakerBalanceThresholdWrapper.getOrderInfoAsync(
- signedOrder,
- );
- const saltAsBigNumber = new BigNumber(salt);
- if (saltAsBigNumber.isLessThanOrEqualTo(cancelOrdersUpToThisSalt)) {
- return expect(orderInfoAfterCancelling.orderStatus).to.be.equal(OrderStatus.Cancelled);
- } else {
- return expect(orderInfoAfterCancelling.orderStatus).to.be.equal(OrderStatus.Fillable);
- }
- });
- });
- it('Should successfully batch cancel order if maker does not meet balance threshold', async () => {
- // Create orders to cancel
- const invalidSignedOrders = [
- await invalidOrderFactory.newSignedOrderAsync({ salt: new BigNumber(0) }),
- await invalidOrderFactory.newSignedOrderAsync({ salt: new BigNumber(1) }),
- await invalidOrderFactory.newSignedOrderAsync({ salt: new BigNumber(2) }),
- ];
- // Verify orders are not cancelled
- _.each(invalidSignedOrders, async signedOrder => {
- const orderInfoBeforeCancelling = await erc721NonValidBalanceThresholdWrapper.getOrderInfoAsync(
- signedOrder,
- );
- return expect(orderInfoBeforeCancelling.orderStatus).to.be.equal(OrderStatus.Fillable);
- });
- // Cancel
- const cancelOrdersUpToThisSalt = new BigNumber(1);
- const txReceipt = await erc721NonValidBalanceThresholdWrapper.cancelOrdersUpToAsync(
- cancelOrdersUpToThisSalt,
- invalidAddress,
- );
- // Assert validated addresses
- const expectedValidatedAddresseses: string[] = [];
- await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
- // Check that order was cancelled
- _.each(invalidSignedOrders, async (signedOrder, salt: number) => {
- const orderInfoAfterCancelling = await erc721NonValidBalanceThresholdWrapper.getOrderInfoAsync(
- signedOrder,
- );
- const saltAsBigNumber = new BigNumber(salt);
- if (saltAsBigNumber.isLessThanOrEqualTo(cancelOrdersUpToThisSalt)) {
- return expect(orderInfoAfterCancelling.orderStatus).to.be.equal(OrderStatus.Cancelled);
- } else {
- return expect(orderInfoAfterCancelling.orderStatus).to.be.equal(OrderStatus.Fillable);
- }
- });
- });
- });
-});
-// tslint:disable:max-file-line-count
-// tslint:enable:no-unnecessary-type-assertion
diff --git a/contracts/extensions/test/extensions/dutch_auction.ts b/contracts/extensions/test/extensions/dutch_auction.ts
deleted file mode 100644
index 22b3caa16..000000000
--- a/contracts/extensions/test/extensions/dutch_auction.ts
+++ /dev/null
@@ -1,378 +0,0 @@
-import { DutchAuctionWrapper } from '@0x/contract-wrappers';
-import {
- artifacts as protocolArtifacts,
- ERC20Wrapper,
- ERC721Wrapper,
- ExchangeContract,
- ExchangeWrapper,
-} from '@0x/contracts-protocol';
-import {
- chaiSetup,
- constants,
- ContractName,
- ERC20BalancesByOwner,
- expectTransactionFailedAsync,
- getLatestBlockTimestampAsync,
- OrderFactory,
- provider,
- txDefaults,
- web3Wrapper,
-} from '@0x/contracts-test-utils';
-import {
- artifacts as tokensArtifacts,
- DummyERC20TokenContract,
- DummyERC721TokenContract,
- WETH9Contract,
-} from '@0x/contracts-tokens';
-import { BlockchainLifecycle } from '@0x/dev-utils';
-import { assetDataUtils, generatePseudoRandomSalt } from '@0x/order-utils';
-import { RevertReason, SignedOrder } from '@0x/types';
-import { BigNumber } from '@0x/utils';
-import { Web3Wrapper } from '@0x/web3-wrapper';
-import * as chai from 'chai';
-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;
-const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
-const DECIMALS_DEFAULT = 18;
-
-describe(ContractName.DutchAuction, () => {
- let makerAddress: string;
- let owner: string;
- let takerAddress: string;
- let feeRecipientAddress: string;
- let defaultMakerAssetAddress: string;
-
- let zrxToken: DummyERC20TokenContract;
- let erc20TokenA: DummyERC20TokenContract;
- let erc721Token: DummyERC721TokenContract;
- let dutchAuctionContract: DutchAuctionContract;
- let wethContract: WETH9Contract;
-
- let sellerOrderFactory: OrderFactory;
- let buyerOrderFactory: OrderFactory;
- let erc20Wrapper: ERC20Wrapper;
- let erc20Balances: ERC20BalancesByOwner;
- let currentBlockTimestamp: number;
- let auctionBeginTimeSeconds: BigNumber;
- let auctionEndTimeSeconds: BigNumber;
- let auctionBeginAmount: BigNumber;
- let auctionEndAmount: BigNumber;
- let sellOrder: SignedOrder;
- let buyOrder: SignedOrder;
- let erc721MakerAssetIds: BigNumber[];
- const tenMinutesInSeconds = 10 * 60;
-
- let dutchAuctionTestWrapper: DutchAuctionTestWrapper;
- let defaultERC20MakerAssetData: string;
-
- before(async () => {
- await blockchainLifecycle.startAsync();
- const accounts = await web3Wrapper.getAvailableAddressesAsync();
- const usedAddresses = ([owner, makerAddress, takerAddress, feeRecipientAddress] = accounts);
-
- erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner);
-
- const numDummyErc20ToDeploy = 2;
- [erc20TokenA, zrxToken] = await erc20Wrapper.deployDummyTokensAsync(
- numDummyErc20ToDeploy,
- constants.DUMMY_TOKEN_DECIMALS,
- );
- const erc20Proxy = await erc20Wrapper.deployProxyAsync();
- await erc20Wrapper.setBalancesAndAllowancesAsync();
-
- const erc721Wrapper = new ERC721Wrapper(provider, usedAddresses, owner);
- [erc721Token] = await erc721Wrapper.deployDummyTokensAsync();
- const erc721Proxy = await erc721Wrapper.deployProxyAsync();
- await erc721Wrapper.setBalancesAndAllowancesAsync();
- const erc721Balances = await erc721Wrapper.getBalancesAsync();
- erc721MakerAssetIds = erc721Balances[makerAddress][erc721Token.address];
-
- wethContract = await WETH9Contract.deployFrom0xArtifactAsync(tokensArtifacts.WETH9, provider, txDefaults);
- erc20Wrapper.addDummyTokenContract(wethContract as any);
-
- const zrxAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address);
- const exchangeInstance = await ExchangeContract.deployFrom0xArtifactAsync(
- protocolArtifacts.Exchange,
- provider,
- txDefaults,
- zrxAssetData,
- );
- const exchangeWrapper = new ExchangeWrapper(exchangeInstance, provider);
- await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner);
- await exchangeWrapper.registerAssetProxyAsync(erc721Proxy.address, owner);
-
- await erc20Proxy.addAuthorizedAddress.sendTransactionAsync(exchangeInstance.address, {
- from: owner,
- });
- await erc721Proxy.addAuthorizedAddress.sendTransactionAsync(exchangeInstance.address, {
- from: owner,
- });
-
- const dutchAuctionInstance = await DutchAuctionContract.deployFrom0xArtifactAsync(
- artifacts.DutchAuction,
- provider,
- txDefaults,
- exchangeInstance.address,
- );
- dutchAuctionContract = new DutchAuctionContract(
- dutchAuctionInstance.abi,
- dutchAuctionInstance.address,
- provider,
- );
- dutchAuctionTestWrapper = new DutchAuctionTestWrapper(dutchAuctionInstance, provider);
-
- defaultMakerAssetAddress = erc20TokenA.address;
- const defaultTakerAssetAddress = wethContract.address;
-
- // Set up taker WETH balance and allowance
- await web3Wrapper.awaitTransactionSuccessAsync(
- await wethContract.deposit.sendTransactionAsync({
- from: takerAddress,
- value: Web3Wrapper.toBaseUnitAmount(new BigNumber(50), DECIMALS_DEFAULT),
- }),
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await wethContract.approve.sendTransactionAsync(
- erc20Proxy.address,
- constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS,
- { from: takerAddress },
- ),
- );
- web3Wrapper.abiDecoder.addABI(exchangeInstance.abi);
- web3Wrapper.abiDecoder.addABI(zrxToken.abi);
- erc20Wrapper.addTokenOwnerAddress(dutchAuctionContract.address);
-
- currentBlockTimestamp = await getLatestBlockTimestampAsync();
- // Default auction begins 10 minutes ago
- auctionBeginTimeSeconds = new BigNumber(currentBlockTimestamp).minus(tenMinutesInSeconds);
- // Default auction ends 10 from now
- auctionEndTimeSeconds = new BigNumber(currentBlockTimestamp).plus(tenMinutesInSeconds);
- auctionBeginAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(10), DECIMALS_DEFAULT);
- auctionEndAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(1), DECIMALS_DEFAULT);
-
- // Default sell order and buy order are exact mirrors
- const sellerDefaultOrderParams = {
- salt: generatePseudoRandomSalt(),
- exchangeAddress: exchangeInstance.address,
- makerAddress,
- feeRecipientAddress,
- // taker address or sender address should be set to the ducth auction contract
- takerAddress: dutchAuctionContract.address,
- makerAssetData: DutchAuctionWrapper.encodeDutchAuctionAssetData(
- assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress),
- auctionBeginTimeSeconds,
- auctionBeginAmount,
- ),
- takerAssetData: assetDataUtils.encodeERC20AssetData(defaultTakerAssetAddress),
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(200), DECIMALS_DEFAULT),
- takerAssetAmount: auctionEndAmount,
- expirationTimeSeconds: auctionEndTimeSeconds,
- makerFee: constants.ZERO_AMOUNT,
- takerFee: constants.ZERO_AMOUNT,
- };
- // Default buy order is for the auction begin price
- const buyerDefaultOrderParams = {
- ...sellerDefaultOrderParams,
- makerAddress: takerAddress,
- makerAssetData: sellerDefaultOrderParams.takerAssetData,
- takerAssetData: sellerDefaultOrderParams.makerAssetData,
- makerAssetAmount: auctionBeginAmount,
- takerAssetAmount: sellerDefaultOrderParams.makerAssetAmount,
- };
- const makerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddress)];
- 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();
- });
- beforeEach(async () => {
- await blockchainLifecycle.startAsync();
- erc20Balances = await erc20Wrapper.getBalancesAsync();
- sellOrder = await sellerOrderFactory.newSignedOrderAsync();
- buyOrder = await buyerOrderFactory.newSignedOrderAsync();
- });
- afterEach(async () => {
- await blockchainLifecycle.revertAsync();
- });
- describe('matchOrders', () => {
- it('should be worth the begin price at the begining of the auction', async () => {
- auctionBeginTimeSeconds = new BigNumber(currentBlockTimestamp + 2);
- 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,
- expirationTimeSeconds: auctionEndTimeSeconds,
- });
- 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 dutchAuctionTestWrapper.getAuctionDetailsAsync(sellOrder);
- buyOrder = await buyerOrderFactory.newSignedOrderAsync({
- makerAssetAmount: beforeAuctionDetails.currentAmount.times(2),
- });
- 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,
- );
- // 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
- // ref: https://github.com/trufflesuite/ganache-core/issues/111
- expect(newBalances[makerAddress][wethContract.address]).to.be.bignumber.gte(
- erc20Balances[makerAddress][wethContract.address].plus(afterAuctionDetails.currentAmount),
- );
- expect(newBalances[takerAddress][wethContract.address]).to.be.bignumber.gte(
- erc20Balances[takerAddress][wethContract.address].minus(beforeAuctionDetails.currentAmount),
- );
- });
- it('maker fees on sellOrder are paid to the fee receipient', async () => {
- sellOrder = await sellerOrderFactory.newSignedOrderAsync({
- makerFee: new BigNumber(1),
- });
- 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),
- );
- expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[feeRecipientAddress][zrxToken.address].plus(sellOrder.makerFee),
- );
- });
- it('maker fees on buyOrder are paid to the fee receipient', async () => {
- buyOrder = await buyerOrderFactory.newSignedOrderAsync({
- makerFee: new BigNumber(1),
- });
- await dutchAuctionTestWrapper.matchOrdersAsync(buyOrder, sellOrder, takerAddress);
- const newBalances = await erc20Wrapper.getBalancesAsync();
- const afterAuctionDetails = await dutchAuctionTestWrapper.getAuctionDetailsAsync(sellOrder);
- expect(newBalances[makerAddress][wethContract.address]).to.be.bignumber.gte(
- erc20Balances[makerAddress][wethContract.address].plus(afterAuctionDetails.currentAmount),
- );
- expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[feeRecipientAddress][zrxToken.address].plus(buyOrder.makerFee),
- );
- });
- 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,
- });
- return expectTransactionFailedAsync(
- dutchAuctionTestWrapper.matchOrdersAsync(buyOrder, sellOrder, takerAddress),
- RevertReason.AuctionExpired,
- );
- });
- it('cannot be filled for less than the current price', async () => {
- buyOrder = await buyerOrderFactory.newSignedOrderAsync({
- makerAssetAmount: sellOrder.takerAssetAmount,
- });
- return expectTransactionFailedAsync(
- dutchAuctionTestWrapper.matchOrdersAsync(buyOrder, sellOrder, takerAddress),
- RevertReason.AuctionInvalidAmount,
- );
- });
- it('auction begin amount must be higher than final amount ', async () => {
- sellOrder = await sellerOrderFactory.newSignedOrderAsync({
- takerAssetAmount: auctionBeginAmount.plus(1),
- });
- return expectTransactionFailedAsync(
- 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,
- });
- return expectTransactionFailedAsync(
- dutchAuctionTestWrapper.matchOrdersAsync(buyOrder, sellOrder, takerAddress),
- RevertReason.AuctionInvalidBeginTime,
- );
- });
- it('asset data contains auction parameters', async () => {
- sellOrder = await sellerOrderFactory.newSignedOrderAsync({
- makerAssetData: assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress),
- });
- return expectTransactionFailedAsync(
- 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,
- });
- buyOrder = await buyerOrderFactory.newSignedOrderAsync({
- takerAssetAmount: new BigNumber(1),
- takerAssetData: sellOrder.makerAssetData,
- });
- 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
- // ref: https://github.com/trufflesuite/ganache-core/issues/111
- expect(newBalances[makerAddress][wethContract.address]).to.be.bignumber.gte(
- erc20Balances[makerAddress][wethContract.address].plus(afterAuctionDetails.currentAmount),
- );
- const newOwner = await erc721Token.ownerOf.callAsync(makerAssetId);
- expect(newOwner).to.be.bignumber.equal(takerAddress);
- });
- });
- });
-});
diff --git a/contracts/extensions/test/extensions/forwarder.ts b/contracts/extensions/test/extensions/forwarder.ts
deleted file mode 100644
index 69939ed04..000000000
--- a/contracts/extensions/test/extensions/forwarder.ts
+++ /dev/null
@@ -1,1291 +0,0 @@
-import {
- artifacts as protocolArtifacts,
- ERC20Wrapper,
- ERC721Wrapper,
- ExchangeContract,
- ExchangeWrapper,
-} from '@0x/contracts-protocol';
-import {
- chaiSetup,
- constants,
- ContractName,
- ERC20BalancesByOwner,
- expectContractCreationFailedAsync,
- expectTransactionFailedAsync,
- OrderFactory,
- provider,
- sendTransactionResult,
- txDefaults,
- web3Wrapper,
-} from '@0x/contracts-test-utils';
-import {
- artifacts as tokenArtifacts,
- DummyERC20TokenContract,
- DummyERC721TokenContract,
- WETH9Contract,
-} from '@0x/contracts-tokens';
-import { BlockchainLifecycle } from '@0x/dev-utils';
-import { assetDataUtils } from '@0x/order-utils';
-import { RevertReason, SignedOrder } from '@0x/types';
-import { BigNumber } from '@0x/utils';
-import { Web3Wrapper } from '@0x/web3-wrapper';
-import * as chai from 'chai';
-import { TransactionReceiptWithDecodedLogs } from 'ethereum-types';
-
-import { ForwarderContract } from '../../generated-wrappers/forwarder';
-import { artifacts } from '../../src/artifacts';
-
-import { ForwarderWrapper } from '../utils/forwarder_wrapper';
-
-chaiSetup.configure();
-const expect = chai.expect;
-const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
-const DECIMALS_DEFAULT = 18;
-const MAX_WETH_FILL_PERCENTAGE = 95;
-
-describe(ContractName.Forwarder, () => {
- let makerAddress: string;
- let owner: string;
- let takerAddress: string;
- let feeRecipientAddress: string;
- let defaultMakerAssetAddress: string;
- let zrxAssetData: string;
- let wethAssetData: string;
-
- let weth: DummyERC20TokenContract;
- let zrxToken: DummyERC20TokenContract;
- let erc20TokenA: DummyERC20TokenContract;
- let erc721Token: DummyERC721TokenContract;
- let forwarderContract: ForwarderContract;
- let wethContract: WETH9Contract;
- let forwarderWrapper: ForwarderWrapper;
- let exchangeWrapper: ExchangeWrapper;
-
- let orderWithoutFee: SignedOrder;
- let orderWithFee: SignedOrder;
- let feeOrder: SignedOrder;
- let orderFactory: OrderFactory;
- let erc20Wrapper: ERC20Wrapper;
- let erc20Balances: ERC20BalancesByOwner;
- let tx: TransactionReceiptWithDecodedLogs;
-
- let erc721MakerAssetIds: BigNumber[];
- let takerEthBalanceBefore: BigNumber;
- let feePercentage: BigNumber;
- let gasPrice: BigNumber;
-
- before(async () => {
- await blockchainLifecycle.startAsync();
- const accounts = await web3Wrapper.getAvailableAddressesAsync();
- 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);
- gasPrice = new BigNumber(transaction.gasPrice);
-
- const erc721Wrapper = new ERC721Wrapper(provider, usedAddresses, owner);
- erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner);
-
- const numDummyErc20ToDeploy = 3;
- [erc20TokenA, zrxToken] = await erc20Wrapper.deployDummyTokensAsync(
- numDummyErc20ToDeploy,
- constants.DUMMY_TOKEN_DECIMALS,
- );
- const erc20Proxy = await erc20Wrapper.deployProxyAsync();
- await erc20Wrapper.setBalancesAndAllowancesAsync();
-
- [erc721Token] = await erc721Wrapper.deployDummyTokensAsync();
- const erc721Proxy = await erc721Wrapper.deployProxyAsync();
- await erc721Wrapper.setBalancesAndAllowancesAsync();
- const erc721Balances = await erc721Wrapper.getBalancesAsync();
- erc721MakerAssetIds = erc721Balances[makerAddress][erc721Token.address];
-
- wethContract = await WETH9Contract.deployFrom0xArtifactAsync(tokenArtifacts.WETH9, provider, txDefaults);
- weth = new DummyERC20TokenContract(wethContract.abi, wethContract.address, provider);
- erc20Wrapper.addDummyTokenContract(weth);
-
- wethAssetData = assetDataUtils.encodeERC20AssetData(wethContract.address);
- zrxAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address);
- const exchangeInstance = await ExchangeContract.deployFrom0xArtifactAsync(
- protocolArtifacts.Exchange,
- provider,
- txDefaults,
- zrxAssetData,
- );
- exchangeWrapper = new ExchangeWrapper(exchangeInstance, provider);
- await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner);
- await exchangeWrapper.registerAssetProxyAsync(erc721Proxy.address, owner);
-
- await erc20Proxy.addAuthorizedAddress.sendTransactionAsync(exchangeInstance.address, {
- from: owner,
- });
- await erc721Proxy.addAuthorizedAddress.sendTransactionAsync(exchangeInstance.address, {
- from: owner,
- });
-
- defaultMakerAssetAddress = erc20TokenA.address;
- const defaultTakerAssetAddress = wethContract.address;
- const defaultOrderParams = {
- exchangeAddress: exchangeInstance.address,
- makerAddress,
- feeRecipientAddress,
- makerAssetData: assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress),
- takerAssetData: assetDataUtils.encodeERC20AssetData(defaultTakerAssetAddress),
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(200), DECIMALS_DEFAULT),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), DECIMALS_DEFAULT),
- makerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), DECIMALS_DEFAULT),
- takerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(0), DECIMALS_DEFAULT),
- };
- const privateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddress)];
- orderFactory = new OrderFactory(privateKey, defaultOrderParams);
-
- const forwarderInstance = await ForwarderContract.deployFrom0xArtifactAsync(
- artifacts.Forwarder,
- provider,
- txDefaults,
- exchangeInstance.address,
- zrxAssetData,
- wethAssetData,
- );
- forwarderContract = new ForwarderContract(forwarderInstance.abi, forwarderInstance.address, provider);
- forwarderWrapper = new ForwarderWrapper(forwarderContract, provider);
- const zrxDepositAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(10000), 18);
- await web3Wrapper.awaitTransactionSuccessAsync(
- await zrxToken.transfer.sendTransactionAsync(forwarderContract.address, zrxDepositAmount),
- );
- erc20Wrapper.addTokenOwnerAddress(forwarderInstance.address);
- });
- after(async () => {
- await blockchainLifecycle.revertAsync();
- });
- beforeEach(async () => {
- await blockchainLifecycle.startAsync();
- erc20Balances = await erc20Wrapper.getBalancesAsync();
- takerEthBalanceBefore = await web3Wrapper.getBalanceInWeiAsync(takerAddress);
- orderWithoutFee = await orderFactory.newSignedOrderAsync();
- feeOrder = await orderFactory.newSignedOrderAsync({
- makerAssetData: assetDataUtils.encodeERC20AssetData(zrxToken.address),
- takerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), DECIMALS_DEFAULT),
- });
- orderWithFee = await orderFactory.newSignedOrderAsync({
- takerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), DECIMALS_DEFAULT),
- });
- });
- afterEach(async () => {
- await blockchainLifecycle.revertAsync();
- });
-
- describe('constructor', () => {
- it('should revert if assetProxy is unregistered', async () => {
- const exchangeInstance = await ExchangeContract.deployFrom0xArtifactAsync(
- protocolArtifacts.Exchange,
- provider,
- txDefaults,
- zrxAssetData,
- );
- return expectContractCreationFailedAsync(
- (ForwarderContract.deployFrom0xArtifactAsync(
- artifacts.Forwarder,
- provider,
- txDefaults,
- exchangeInstance.address,
- zrxAssetData,
- wethAssetData,
- ) as any) as sendTransactionResult,
- RevertReason.UnregisteredAssetProxy,
- );
- });
- });
- describe('marketSellOrdersWithEth without extra fees', () => {
- it('should fill a single order', async () => {
- const ordersWithoutFee = [orderWithoutFee];
- const feeOrders: SignedOrder[] = [];
- const ethValue = orderWithoutFee.takerAssetAmount.dividedToIntegerBy(2);
-
- tx = await forwarderWrapper.marketSellOrdersWithEthAsync(ordersWithoutFee, feeOrders, {
- value: ethValue,
- from: takerAddress,
- });
- const takerEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(takerAddress);
- const forwarderEthBalance = await web3Wrapper.getBalanceInWeiAsync(forwarderContract.address);
- const newBalances = await erc20Wrapper.getBalancesAsync();
-
- const primaryTakerAssetFillAmount = ForwarderWrapper.getPercentageOfValue(
- ethValue,
- MAX_WETH_FILL_PERCENTAGE,
- );
- const makerAssetFillAmount = primaryTakerAssetFillAmount
- .times(orderWithoutFee.makerAssetAmount)
- .dividedToIntegerBy(orderWithoutFee.takerAssetAmount);
- const totalEthSpent = primaryTakerAssetFillAmount.plus(gasPrice.times(tx.gasUsed));
-
- expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent));
- expect(newBalances[makerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount),
- );
- expect(newBalances[takerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultMakerAssetAddress].plus(makerAssetFillAmount),
- );
- expect(newBalances[makerAddress][weth.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][weth.address].plus(primaryTakerAssetFillAmount),
- );
- expect(newBalances[forwarderContract.address][weth.address]).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(newBalances[forwarderContract.address][defaultMakerAssetAddress]).to.be.bignumber.equal(
- constants.ZERO_AMOUNT,
- );
- expect(forwarderEthBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- });
- it('should fill multiple orders', async () => {
- const secondOrderWithoutFee = await orderFactory.newSignedOrderAsync();
- const ordersWithoutFee = [orderWithoutFee, secondOrderWithoutFee];
- const feeOrders: SignedOrder[] = [];
- const ethValue = ordersWithoutFee[0].takerAssetAmount.plus(
- ordersWithoutFee[1].takerAssetAmount.dividedToIntegerBy(2),
- );
-
- tx = await forwarderWrapper.marketSellOrdersWithEthAsync(ordersWithoutFee, feeOrders, {
- value: ethValue,
- from: takerAddress,
- });
- const takerEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(takerAddress);
- const forwarderEthBalance = await web3Wrapper.getBalanceInWeiAsync(forwarderContract.address);
- const newBalances = await erc20Wrapper.getBalancesAsync();
-
- const primaryTakerAssetFillAmount = ForwarderWrapper.getPercentageOfValue(
- ethValue,
- MAX_WETH_FILL_PERCENTAGE,
- );
- const firstTakerAssetFillAmount = ordersWithoutFee[0].takerAssetAmount;
- const secondTakerAssetFillAmount = primaryTakerAssetFillAmount.minus(firstTakerAssetFillAmount);
-
- const makerAssetFillAmount = ordersWithoutFee[0].makerAssetAmount.plus(
- ordersWithoutFee[1].makerAssetAmount
- .times(secondTakerAssetFillAmount)
- .dividedToIntegerBy(ordersWithoutFee[1].takerAssetAmount),
- );
- const totalEthSpent = primaryTakerAssetFillAmount.plus(gasPrice.times(tx.gasUsed));
- expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent));
- expect(newBalances[makerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount),
- );
- expect(newBalances[takerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultMakerAssetAddress].plus(makerAssetFillAmount),
- );
- expect(newBalances[makerAddress][weth.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][weth.address].plus(primaryTakerAssetFillAmount),
- );
- expect(newBalances[forwarderContract.address][weth.address]).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(newBalances[forwarderContract.address][defaultMakerAssetAddress]).to.be.bignumber.equal(
- constants.ZERO_AMOUNT,
- );
- expect(forwarderEthBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- });
- it('should fill the order and pay ZRX fees from a single feeOrder', async () => {
- const ordersWithFee = [orderWithFee];
- const feeOrders = [feeOrder];
- const ethValue = orderWithFee.takerAssetAmount.dividedToIntegerBy(2);
-
- tx = await forwarderWrapper.marketSellOrdersWithEthAsync(ordersWithFee, feeOrders, {
- value: ethValue,
- from: takerAddress,
- });
- const takerEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(takerAddress);
- const forwarderEthBalance = await web3Wrapper.getBalanceInWeiAsync(forwarderContract.address);
- const newBalances = await erc20Wrapper.getBalancesAsync();
-
- const primaryTakerAssetFillAmount = ForwarderWrapper.getPercentageOfValue(
- ethValue,
- MAX_WETH_FILL_PERCENTAGE,
- );
- const makerAssetFillAmount = primaryTakerAssetFillAmount
- .times(orderWithoutFee.makerAssetAmount)
- .dividedToIntegerBy(orderWithoutFee.takerAssetAmount);
- const feeAmount = ForwarderWrapper.getPercentageOfValue(
- orderWithFee.takerFee.dividedToIntegerBy(2),
- MAX_WETH_FILL_PERCENTAGE,
- );
- const wethSpentOnFeeOrders = ForwarderWrapper.getWethForFeeOrders(feeAmount, feeOrders);
- const totalEthSpent = primaryTakerAssetFillAmount
- .plus(wethSpentOnFeeOrders)
- .plus(gasPrice.times(tx.gasUsed));
-
- expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent));
- expect(newBalances[makerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount),
- );
- expect(newBalances[takerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultMakerAssetAddress].plus(makerAssetFillAmount),
- );
- expect(newBalances[makerAddress][weth.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][weth.address].plus(primaryTakerAssetFillAmount).plus(wethSpentOnFeeOrders),
- );
- expect(newBalances[forwarderContract.address][weth.address]).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(newBalances[forwarderContract.address][defaultMakerAssetAddress]).to.be.bignumber.equal(
- constants.ZERO_AMOUNT,
- );
- expect(forwarderEthBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- });
- it('should fill the orders and pay ZRX from multiple feeOrders', async () => {
- const ordersWithFee = [orderWithFee];
- const ethValue = orderWithFee.takerAssetAmount;
- const makerAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address);
- const makerAssetAmount = orderWithFee.takerFee.dividedToIntegerBy(2);
- const takerAssetAmount = feeOrder.takerAssetAmount
- .times(makerAssetAmount)
- .dividedToIntegerBy(feeOrder.makerAssetAmount);
-
- const firstFeeOrder = await orderFactory.newSignedOrderAsync({
- makerAssetData,
- makerAssetAmount,
- takerAssetAmount,
- });
- const secondFeeOrder = await orderFactory.newSignedOrderAsync({
- makerAssetData,
- makerAssetAmount,
- takerAssetAmount,
- });
- const feeOrders = [firstFeeOrder, secondFeeOrder];
-
- tx = await forwarderWrapper.marketSellOrdersWithEthAsync(ordersWithFee, feeOrders, {
- value: ethValue,
- from: takerAddress,
- });
- const takerEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(takerAddress);
- const forwarderEthBalance = await web3Wrapper.getBalanceInWeiAsync(forwarderContract.address);
- const newBalances = await erc20Wrapper.getBalancesAsync();
-
- const primaryTakerAssetFillAmount = ForwarderWrapper.getPercentageOfValue(
- ethValue,
- MAX_WETH_FILL_PERCENTAGE,
- );
- const makerAssetFillAmount = primaryTakerAssetFillAmount
- .times(orderWithoutFee.makerAssetAmount)
- .dividedToIntegerBy(orderWithoutFee.takerAssetAmount);
- const feeAmount = ForwarderWrapper.getPercentageOfValue(orderWithFee.takerFee, MAX_WETH_FILL_PERCENTAGE);
- const wethSpentOnFeeOrders = ForwarderWrapper.getWethForFeeOrders(feeAmount, feeOrders);
- const totalEthSpent = primaryTakerAssetFillAmount
- .plus(wethSpentOnFeeOrders)
- .plus(gasPrice.times(tx.gasUsed));
-
- expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent));
- expect(newBalances[makerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount),
- );
- expect(newBalances[takerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultMakerAssetAddress].plus(makerAssetFillAmount),
- );
- expect(newBalances[makerAddress][weth.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][weth.address].plus(primaryTakerAssetFillAmount).plus(wethSpentOnFeeOrders),
- );
- expect(newBalances[forwarderContract.address][weth.address]).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(newBalances[forwarderContract.address][defaultMakerAssetAddress]).to.be.bignumber.equal(
- constants.ZERO_AMOUNT,
- );
- expect(forwarderEthBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- });
- it('should fill the order when token is ZRX with fees', async () => {
- orderWithFee = await orderFactory.newSignedOrderAsync({
- makerAssetData: assetDataUtils.encodeERC20AssetData(zrxToken.address),
- takerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), DECIMALS_DEFAULT),
- });
- const ordersWithFee = [orderWithFee];
- const feeOrders: SignedOrder[] = [];
- const ethValue = orderWithFee.takerAssetAmount.dividedToIntegerBy(2);
-
- tx = await forwarderWrapper.marketSellOrdersWithEthAsync(ordersWithFee, feeOrders, {
- value: ethValue,
- from: takerAddress,
- });
- const takerEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(takerAddress);
- const forwarderEthBalance = await web3Wrapper.getBalanceInWeiAsync(forwarderContract.address);
- const newBalances = await erc20Wrapper.getBalancesAsync();
-
- const makerAssetFillAmount = orderWithFee.makerAssetAmount.dividedToIntegerBy(2);
- const totalEthSpent = ethValue.plus(gasPrice.times(tx.gasUsed));
- const takerFeePaid = orderWithFee.takerFee.dividedToIntegerBy(2);
- const makerFeePaid = orderWithFee.makerFee.dividedToIntegerBy(2);
-
- expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent));
- expect(newBalances[makerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][zrxToken.address].minus(makerAssetFillAmount).minus(makerFeePaid),
- );
- expect(newBalances[takerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[takerAddress][zrxToken.address].plus(makerAssetFillAmount).minus(takerFeePaid),
- );
- expect(newBalances[makerAddress][weth.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][weth.address].plus(ethValue),
- );
- expect(newBalances[forwarderContract.address][weth.address]).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(newBalances[forwarderContract.address][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[forwarderContract.address][zrxToken.address],
- );
- expect(forwarderEthBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- });
- it('should refund remaining ETH if amount is greater than takerAssetAmount', async () => {
- const ordersWithoutFee = [orderWithoutFee];
- const feeOrders: SignedOrder[] = [];
- const ethValue = orderWithoutFee.takerAssetAmount.times(2);
-
- tx = await forwarderWrapper.marketSellOrdersWithEthAsync(ordersWithoutFee, feeOrders, {
- value: ethValue,
- from: takerAddress,
- });
- const takerEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(takerAddress);
- const totalEthSpent = orderWithoutFee.takerAssetAmount.plus(gasPrice.times(tx.gasUsed));
-
- expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent));
- });
- it('should revert if ZRX cannot be fully repurchased', async () => {
- orderWithFee = await orderFactory.newSignedOrderAsync({
- takerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(50), DECIMALS_DEFAULT),
- });
- const ordersWithFee = [orderWithFee];
- feeOrder = await orderFactory.newSignedOrderAsync({
- makerAssetData: assetDataUtils.encodeERC20AssetData(zrxToken.address),
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), DECIMALS_DEFAULT),
- });
- const feeOrders = [feeOrder];
- const ethValue = orderWithFee.takerAssetAmount;
- return expectTransactionFailedAsync(
- forwarderWrapper.marketSellOrdersWithEthAsync(ordersWithFee, feeOrders, {
- value: ethValue,
- from: takerAddress,
- }),
- RevertReason.CompleteFillFailed,
- );
- });
- it('should not fill orders with different makerAssetData than the first order', async () => {
- const makerAssetId = erc721MakerAssetIds[0];
- const erc721SignedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetAmount: new BigNumber(1),
- makerAssetData: assetDataUtils.encodeERC721AssetData(erc721Token.address, makerAssetId),
- });
- const erc20SignedOrder = await orderFactory.newSignedOrderAsync();
- const ordersWithoutFee = [erc20SignedOrder, erc721SignedOrder];
- const feeOrders: SignedOrder[] = [];
- const ethValue = erc20SignedOrder.takerAssetAmount.plus(erc721SignedOrder.takerAssetAmount);
-
- tx = await forwarderWrapper.marketSellOrdersWithEthAsync(ordersWithoutFee, feeOrders, {
- value: ethValue,
- from: takerAddress,
- });
- const takerEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(takerAddress);
- const totalEthSpent = erc20SignedOrder.takerAssetAmount.plus(gasPrice.times(tx.gasUsed));
-
- expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent));
- });
- });
- describe('marketSellOrdersWithEth with extra fees', () => {
- it('should fill the order and send fee to feeRecipient', async () => {
- const ordersWithoutFee = [orderWithoutFee];
- const feeOrders: SignedOrder[] = [];
- const ethValue = orderWithoutFee.takerAssetAmount.div(2);
-
- const baseFeePercentage = 2;
- feePercentage = ForwarderWrapper.getPercentageOfValue(constants.PERCENTAGE_DENOMINATOR, baseFeePercentage);
- const feeRecipientEthBalanceBefore = await web3Wrapper.getBalanceInWeiAsync(feeRecipientAddress);
- tx = await forwarderWrapper.marketSellOrdersWithEthAsync(
- ordersWithoutFee,
- feeOrders,
- {
- value: ethValue,
- from: takerAddress,
- },
- { feePercentage, feeRecipient: feeRecipientAddress },
- );
- const takerEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(takerAddress);
- const feeRecipientEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(feeRecipientAddress);
- const forwarderEthBalance = await web3Wrapper.getBalanceInWeiAsync(forwarderContract.address);
- const newBalances = await erc20Wrapper.getBalancesAsync();
-
- const primaryTakerAssetFillAmount = ForwarderWrapper.getPercentageOfValue(
- ethValue,
- MAX_WETH_FILL_PERCENTAGE,
- );
- const makerAssetFillAmount = primaryTakerAssetFillAmount
- .times(orderWithoutFee.makerAssetAmount)
- .dividedToIntegerBy(orderWithoutFee.takerAssetAmount);
- const ethSpentOnFee = ForwarderWrapper.getPercentageOfValue(primaryTakerAssetFillAmount, baseFeePercentage);
- const totalEthSpent = primaryTakerAssetFillAmount.plus(ethSpentOnFee).plus(gasPrice.times(tx.gasUsed));
-
- expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent));
- expect(newBalances[makerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount),
- );
- expect(newBalances[takerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultMakerAssetAddress].plus(makerAssetFillAmount),
- );
- expect(newBalances[makerAddress][weth.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][weth.address].plus(primaryTakerAssetFillAmount),
- );
- expect(newBalances[forwarderContract.address][weth.address]).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(newBalances[forwarderContract.address][defaultMakerAssetAddress]).to.be.bignumber.equal(
- constants.ZERO_AMOUNT,
- );
- expect(feeRecipientEthBalanceAfter).to.be.bignumber.equal(feeRecipientEthBalanceBefore.plus(ethSpentOnFee));
- expect(forwarderEthBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- });
- it('should fail if the fee is set too high', async () => {
- const ethValue = orderWithoutFee.takerAssetAmount.div(2);
- const baseFeePercentage = 6;
- feePercentage = ForwarderWrapper.getPercentageOfValue(ethValue, baseFeePercentage);
- const ordersWithoutFee = [orderWithoutFee];
- const feeOrders: SignedOrder[] = [];
- await expectTransactionFailedAsync(
- forwarderWrapper.marketSellOrdersWithEthAsync(
- ordersWithoutFee,
- feeOrders,
- { from: takerAddress, value: ethValue, gasPrice },
- { feePercentage, feeRecipient: feeRecipientAddress },
- ),
- RevertReason.FeePercentageTooLarge,
- );
- });
- it('should fail if there is not enough ETH remaining to pay the fee', async () => {
- const ethValue = orderWithoutFee.takerAssetAmount.div(2);
- const baseFeePercentage = 5;
- feePercentage = ForwarderWrapper.getPercentageOfValue(constants.PERCENTAGE_DENOMINATOR, baseFeePercentage);
- const ordersWithFee = [orderWithFee];
- const feeOrders = [feeOrder];
- await expectTransactionFailedAsync(
- forwarderWrapper.marketSellOrdersWithEthAsync(
- ordersWithFee,
- feeOrders,
- { from: takerAddress, value: ethValue, gasPrice },
- { feePercentage, feeRecipient: feeRecipientAddress },
- ),
- RevertReason.InsufficientEthRemaining,
- );
- });
- });
- describe('marketBuyOrdersWithEth without extra fees', () => {
- it('should buy the exact amount of makerAsset in a single order', async () => {
- const ordersWithoutFee = [orderWithoutFee];
- const feeOrders: SignedOrder[] = [];
- const makerAssetFillAmount = orderWithoutFee.makerAssetAmount.dividedToIntegerBy(2);
- const ethValue = orderWithoutFee.takerAssetAmount.dividedToIntegerBy(2);
-
- tx = await forwarderWrapper.marketBuyOrdersWithEthAsync(ordersWithoutFee, feeOrders, makerAssetFillAmount, {
- value: ethValue,
- from: takerAddress,
- });
- const takerEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(takerAddress);
- const forwarderEthBalance = await web3Wrapper.getBalanceInWeiAsync(forwarderContract.address);
- const newBalances = await erc20Wrapper.getBalancesAsync();
-
- const primaryTakerAssetFillAmount = ethValue;
- const totalEthSpent = primaryTakerAssetFillAmount.plus(gasPrice.times(tx.gasUsed));
-
- expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent));
- expect(newBalances[makerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount),
- );
- expect(newBalances[takerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultMakerAssetAddress].plus(makerAssetFillAmount),
- );
- expect(newBalances[makerAddress][weth.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][weth.address].plus(primaryTakerAssetFillAmount),
- );
- expect(newBalances[forwarderContract.address][weth.address]).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(newBalances[forwarderContract.address][defaultMakerAssetAddress]).to.be.bignumber.equal(
- constants.ZERO_AMOUNT,
- );
- expect(forwarderEthBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- });
- it('should buy the exact amount of makerAsset in multiple orders', async () => {
- const secondOrderWithoutFee = await orderFactory.newSignedOrderAsync();
- const ordersWithoutFee = [orderWithoutFee, secondOrderWithoutFee];
- const feeOrders: SignedOrder[] = [];
- const makerAssetFillAmount = ordersWithoutFee[0].makerAssetAmount.plus(
- ordersWithoutFee[1].makerAssetAmount.dividedToIntegerBy(2),
- );
- const ethValue = ordersWithoutFee[0].takerAssetAmount.plus(
- ordersWithoutFee[1].takerAssetAmount.dividedToIntegerBy(2),
- );
-
- tx = await forwarderWrapper.marketBuyOrdersWithEthAsync(ordersWithoutFee, feeOrders, makerAssetFillAmount, {
- value: ethValue,
- from: takerAddress,
- });
- const takerEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(takerAddress);
- const forwarderEthBalance = await web3Wrapper.getBalanceInWeiAsync(forwarderContract.address);
- const newBalances = await erc20Wrapper.getBalancesAsync();
-
- const primaryTakerAssetFillAmount = ethValue;
- const totalEthSpent = primaryTakerAssetFillAmount.plus(gasPrice.times(tx.gasUsed));
-
- expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent));
- expect(newBalances[makerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount),
- );
- expect(newBalances[takerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultMakerAssetAddress].plus(makerAssetFillAmount),
- );
- expect(newBalances[makerAddress][weth.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][weth.address].plus(primaryTakerAssetFillAmount),
- );
- expect(newBalances[forwarderContract.address][weth.address]).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(newBalances[forwarderContract.address][defaultMakerAssetAddress]).to.be.bignumber.equal(
- constants.ZERO_AMOUNT,
- );
- expect(forwarderEthBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- });
- it('should buy the exact amount of makerAsset and return excess ETH', async () => {
- const ordersWithoutFee = [orderWithoutFee];
- const feeOrders: SignedOrder[] = [];
- const makerAssetFillAmount = orderWithoutFee.makerAssetAmount.dividedToIntegerBy(2);
- const ethValue = orderWithoutFee.takerAssetAmount;
-
- tx = await forwarderWrapper.marketBuyOrdersWithEthAsync(ordersWithoutFee, feeOrders, makerAssetFillAmount, {
- value: ethValue,
- from: takerAddress,
- });
- const takerEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(takerAddress);
- const forwarderEthBalance = await web3Wrapper.getBalanceInWeiAsync(forwarderContract.address);
- const newBalances = await erc20Wrapper.getBalancesAsync();
-
- const primaryTakerAssetFillAmount = ethValue.dividedToIntegerBy(2);
- const totalEthSpent = primaryTakerAssetFillAmount.plus(gasPrice.times(tx.gasUsed));
-
- expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent));
- expect(newBalances[makerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount),
- );
- expect(newBalances[takerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultMakerAssetAddress].plus(makerAssetFillAmount),
- );
- expect(newBalances[makerAddress][weth.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][weth.address].plus(primaryTakerAssetFillAmount),
- );
- expect(newBalances[forwarderContract.address][weth.address]).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(newBalances[forwarderContract.address][defaultMakerAssetAddress]).to.be.bignumber.equal(
- constants.ZERO_AMOUNT,
- );
- expect(forwarderEthBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- });
- it('should buy the exact amount of makerAsset and pay ZRX from feeOrders', async () => {
- const ordersWithFee = [orderWithFee];
- const feeOrders = [feeOrder];
- const makerAssetFillAmount = orderWithFee.makerAssetAmount.dividedToIntegerBy(2);
- const ethValue = orderWithFee.takerAssetAmount;
-
- tx = await forwarderWrapper.marketBuyOrdersWithEthAsync(ordersWithFee, feeOrders, makerAssetFillAmount, {
- value: ethValue,
- from: takerAddress,
- });
- const takerEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(takerAddress);
- const forwarderEthBalance = await web3Wrapper.getBalanceInWeiAsync(forwarderContract.address);
- const newBalances = await erc20Wrapper.getBalancesAsync();
-
- const primaryTakerAssetFillAmount = orderWithFee.takerAssetAmount.dividedToIntegerBy(2);
- const feeAmount = orderWithFee.takerFee.dividedToIntegerBy(2);
- const wethSpentOnFeeOrders = ForwarderWrapper.getWethForFeeOrders(feeAmount, feeOrders);
- const totalEthSpent = primaryTakerAssetFillAmount
- .plus(wethSpentOnFeeOrders)
- .plus(gasPrice.times(tx.gasUsed));
-
- expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent));
- expect(newBalances[makerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount),
- );
- expect(newBalances[takerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultMakerAssetAddress].plus(makerAssetFillAmount),
- );
- expect(newBalances[makerAddress][weth.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][weth.address].plus(primaryTakerAssetFillAmount).plus(wethSpentOnFeeOrders),
- );
- expect(newBalances[forwarderContract.address][weth.address]).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(newBalances[forwarderContract.address][defaultMakerAssetAddress]).to.be.bignumber.equal(
- constants.ZERO_AMOUNT,
- );
- expect(forwarderEthBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- });
- it('should buy slightly greater than makerAssetAmount when buying ZRX', async () => {
- orderWithFee = await orderFactory.newSignedOrderAsync({
- makerAssetData: assetDataUtils.encodeERC20AssetData(zrxToken.address),
- takerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), DECIMALS_DEFAULT),
- });
- const ordersWithFee = [orderWithFee];
- const feeOrders: SignedOrder[] = [];
- const makerAssetFillAmount = orderWithFee.makerAssetAmount.dividedToIntegerBy(2);
- const ethValue = orderWithFee.takerAssetAmount;
- tx = await forwarderWrapper.marketBuyOrdersWithEthAsync(ordersWithFee, feeOrders, makerAssetFillAmount, {
- value: ethValue,
- from: takerAddress,
- });
- const takerEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(takerAddress);
- const forwarderEthBalance = await web3Wrapper.getBalanceInWeiAsync(forwarderContract.address);
- const newBalances = await erc20Wrapper.getBalancesAsync();
-
- const primaryTakerAssetFillAmount = ForwarderWrapper.getWethForFeeOrders(
- makerAssetFillAmount,
- ordersWithFee,
- );
- const totalEthSpent = primaryTakerAssetFillAmount.plus(gasPrice.times(tx.gasUsed));
- const makerAssetFilledAmount = orderWithFee.makerAssetAmount
- .times(primaryTakerAssetFillAmount)
- .dividedToIntegerBy(orderWithFee.takerAssetAmount);
- const takerFeePaid = orderWithFee.takerFee
- .times(primaryTakerAssetFillAmount)
- .dividedToIntegerBy(orderWithFee.takerAssetAmount);
- const makerFeePaid = orderWithFee.makerFee
- .times(primaryTakerAssetFillAmount)
- .dividedToIntegerBy(orderWithFee.takerAssetAmount);
- const totalZrxPurchased = makerAssetFilledAmount.minus(takerFeePaid);
- // Up to 1 wei worth of ZRX will be overbought per order
- const maxOverboughtZrx = new BigNumber(1)
- .times(orderWithFee.makerAssetAmount)
- .dividedToIntegerBy(orderWithFee.takerAssetAmount);
-
- expect(totalZrxPurchased).to.be.bignumber.gte(makerAssetFillAmount);
- expect(totalZrxPurchased).to.be.bignumber.lte(makerAssetFillAmount.plus(maxOverboughtZrx));
- expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent));
- expect(newBalances[makerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][zrxToken.address].minus(makerAssetFilledAmount).minus(makerFeePaid),
- );
- expect(newBalances[takerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[takerAddress][zrxToken.address].plus(totalZrxPurchased),
- );
- expect(newBalances[makerAddress][weth.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][weth.address].plus(primaryTakerAssetFillAmount),
- );
- expect(newBalances[forwarderContract.address][weth.address]).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(newBalances[forwarderContract.address][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[forwarderContract.address][zrxToken.address],
- );
- expect(forwarderEthBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- });
- it('should revert if the amount of ETH sent is too low to fill the makerAssetAmount', async () => {
- const ordersWithoutFee = [orderWithoutFee];
- const feeOrders: SignedOrder[] = [];
- const makerAssetFillAmount = orderWithoutFee.makerAssetAmount.dividedToIntegerBy(2);
- const ethValue = orderWithoutFee.takerAssetAmount.dividedToIntegerBy(4);
- return expectTransactionFailedAsync(
- forwarderWrapper.marketBuyOrdersWithEthAsync(ordersWithoutFee, feeOrders, makerAssetFillAmount, {
- value: ethValue,
- from: takerAddress,
- }),
- RevertReason.CompleteFillFailed,
- );
- });
- it('should buy an ERC721 asset from a single order', async () => {
- const makerAssetId = erc721MakerAssetIds[0];
- orderWithoutFee = await orderFactory.newSignedOrderAsync({
- makerAssetAmount: new BigNumber(1),
- makerAssetData: assetDataUtils.encodeERC721AssetData(erc721Token.address, makerAssetId),
- });
- const ordersWithoutFee = [orderWithoutFee];
- const feeOrders: SignedOrder[] = [];
- const makerAssetFillAmount = new BigNumber(1);
- const ethValue = orderWithFee.takerAssetAmount;
-
- tx = await forwarderWrapper.marketBuyOrdersWithEthAsync(ordersWithoutFee, feeOrders, makerAssetFillAmount, {
- from: takerAddress,
- value: ethValue,
- });
- const takerEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(takerAddress);
- const forwarderEthBalance = await web3Wrapper.getBalanceInWeiAsync(forwarderContract.address);
- const newOwner = await erc721Token.ownerOf.callAsync(makerAssetId);
- const newBalances = await erc20Wrapper.getBalancesAsync();
-
- const primaryTakerAssetFillAmount = ethValue;
- const totalEthSpent = primaryTakerAssetFillAmount.plus(gasPrice.times(tx.gasUsed));
- expect(newOwner).to.be.bignumber.equal(takerAddress);
- expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent));
- expect(newBalances[makerAddress][weth.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][weth.address].plus(primaryTakerAssetFillAmount),
- );
- expect(newBalances[forwarderContract.address][weth.address]).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(newBalances[forwarderContract.address][defaultMakerAssetAddress]).to.be.bignumber.equal(
- constants.ZERO_AMOUNT,
- );
- expect(forwarderEthBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- });
- it('should revert if buying an ERC721 asset when later orders contain different makerAssetData', async () => {
- const makerAssetId = erc721MakerAssetIds[0];
- orderWithoutFee = await orderFactory.newSignedOrderAsync({
- makerAssetAmount: new BigNumber(1),
- makerAssetData: assetDataUtils.encodeERC721AssetData(erc721Token.address, makerAssetId),
- });
- const differentMakerAssetDataOrder = await orderFactory.newSignedOrderAsync();
- const ordersWithoutFee = [orderWithoutFee, differentMakerAssetDataOrder];
- const feeOrders: SignedOrder[] = [];
- const makerAssetFillAmount = new BigNumber(1).plus(differentMakerAssetDataOrder.makerAssetAmount);
- const ethValue = orderWithFee.takerAssetAmount;
- return expectTransactionFailedAsync(
- forwarderWrapper.marketBuyOrdersWithEthAsync(ordersWithoutFee, feeOrders, makerAssetFillAmount, {
- value: ethValue,
- from: takerAddress,
- }),
- RevertReason.CompleteFillFailed,
- );
- });
- it('should buy an ERC721 asset and pay ZRX fees from a single fee order', async () => {
- const makerAssetId = erc721MakerAssetIds[0];
- orderWithFee = await orderFactory.newSignedOrderAsync({
- makerAssetAmount: new BigNumber(1),
- makerAssetData: assetDataUtils.encodeERC721AssetData(erc721Token.address, makerAssetId),
- takerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), DECIMALS_DEFAULT),
- });
- const ordersWithFee = [orderWithFee];
- const feeOrders = [feeOrder];
- const makerAssetFillAmount = orderWithFee.makerAssetAmount;
- const primaryTakerAssetFillAmount = orderWithFee.takerAssetAmount;
- const feeAmount = orderWithFee.takerFee;
- const wethSpentOnFeeOrders = ForwarderWrapper.getWethForFeeOrders(feeAmount, feeOrders);
- const ethValue = primaryTakerAssetFillAmount.plus(wethSpentOnFeeOrders);
-
- tx = await forwarderWrapper.marketBuyOrdersWithEthAsync(ordersWithFee, feeOrders, makerAssetFillAmount, {
- value: ethValue,
- from: takerAddress,
- });
- const takerEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(takerAddress);
- const forwarderEthBalance = await web3Wrapper.getBalanceInWeiAsync(forwarderContract.address);
- const newOwner = await erc721Token.ownerOf.callAsync(makerAssetId);
- const newBalances = await erc20Wrapper.getBalancesAsync();
-
- const totalEthSpent = ethValue.plus(gasPrice.times(tx.gasUsed));
-
- expect(newOwner).to.be.bignumber.equal(takerAddress);
- expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent));
- expect(newBalances[makerAddress][weth.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][weth.address].plus(primaryTakerAssetFillAmount).plus(wethSpentOnFeeOrders),
- );
- expect(newBalances[forwarderContract.address][weth.address]).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(newBalances[forwarderContract.address][defaultMakerAssetAddress]).to.be.bignumber.equal(
- constants.ZERO_AMOUNT,
- );
- expect(forwarderEthBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- });
- it('should buy an ERC721 asset and pay ZRX fees from multiple fee orders', async () => {
- const makerAssetId = erc721MakerAssetIds[0];
- orderWithFee = await orderFactory.newSignedOrderAsync({
- makerAssetAmount: new BigNumber(1),
- makerAssetData: assetDataUtils.encodeERC721AssetData(erc721Token.address, makerAssetId),
- takerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), DECIMALS_DEFAULT),
- });
- const ordersWithFee = [orderWithFee];
- const makerAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address);
- const makerAssetAmount = orderWithFee.takerFee.dividedToIntegerBy(2);
- const takerAssetAmount = feeOrder.takerAssetAmount
- .times(makerAssetAmount)
- .dividedToIntegerBy(feeOrder.makerAssetAmount);
-
- const firstFeeOrder = await orderFactory.newSignedOrderAsync({
- makerAssetData,
- makerAssetAmount,
- takerAssetAmount,
- });
- const secondFeeOrder = await orderFactory.newSignedOrderAsync({
- makerAssetData,
- makerAssetAmount,
- takerAssetAmount,
- });
- const feeOrders = [firstFeeOrder, secondFeeOrder];
-
- const makerAssetFillAmount = orderWithFee.makerAssetAmount;
- const primaryTakerAssetFillAmount = orderWithFee.takerAssetAmount;
- const feeAmount = orderWithFee.takerFee;
- const wethSpentOnFeeOrders = ForwarderWrapper.getWethForFeeOrders(feeAmount, feeOrders);
- const ethValue = primaryTakerAssetFillAmount.plus(wethSpentOnFeeOrders);
-
- tx = await forwarderWrapper.marketBuyOrdersWithEthAsync(ordersWithFee, feeOrders, makerAssetFillAmount, {
- value: ethValue,
- from: takerAddress,
- });
- const takerEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(takerAddress);
- const forwarderEthBalance = await web3Wrapper.getBalanceInWeiAsync(forwarderContract.address);
- const newOwner = await erc721Token.ownerOf.callAsync(makerAssetId);
- const newBalances = await erc20Wrapper.getBalancesAsync();
-
- const totalEthSpent = ethValue.plus(gasPrice.times(tx.gasUsed));
-
- expect(newOwner).to.be.bignumber.equal(takerAddress);
- expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent));
- expect(newBalances[makerAddress][weth.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][weth.address].plus(primaryTakerAssetFillAmount).plus(wethSpentOnFeeOrders),
- );
- expect(newBalances[forwarderContract.address][weth.address]).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(newBalances[forwarderContract.address][defaultMakerAssetAddress]).to.be.bignumber.equal(
- constants.ZERO_AMOUNT,
- );
- expect(forwarderEthBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- });
- it('Should buy slightly greater MakerAsset when exchange rate is rounded', async () => {
- // The 0x Protocol contracts round the exchange rate in favor of the Maker.
- // In this case, the taker must round up how much they're going to spend, which
- // in turn increases the amount of MakerAsset being purchased.
- // Example:
- // The taker wants to buy 5 units of the MakerAsset at a rate of 3M/2T.
- // For every 2 units of TakerAsset, the taker will receive 3 units of MakerAsset.
- // To purchase 5 units, the taker must spend 10/3 = 3.33 units of TakerAssset.
- // However, the Taker can only spend whole units.
- // Spending floor(10/3) = 3 units will yield a profit of Floor(3*3/2) = Floor(4.5) = 4 units of MakerAsset.
- // Spending ceil(10/3) = 4 units will yield a profit of Floor(4*3/2) = 6 units of MakerAsset.
- //
- // The forwarding contract will opt for the second option, which overbuys, to ensure the taker
- // receives at least the amount of MakerAsset they requested.
- //
- // Construct test case using values from example above
- orderWithoutFee = await orderFactory.newSignedOrderAsync({
- makerAssetAmount: new BigNumber('30'),
- takerAssetAmount: new BigNumber('20'),
- makerAssetData: assetDataUtils.encodeERC20AssetData(erc20TokenA.address),
- takerAssetData: assetDataUtils.encodeERC20AssetData(weth.address),
- makerFee: new BigNumber(0),
- takerFee: new BigNumber(0),
- });
- const ordersWithoutFee = [orderWithoutFee];
- const feeOrders: SignedOrder[] = [];
- const desiredMakerAssetFillAmount = new BigNumber('5');
- const makerAssetFillAmount = new BigNumber('6');
- const ethValue = new BigNumber('4');
- // Execute test case
- tx = await forwarderWrapper.marketBuyOrdersWithEthAsync(
- ordersWithoutFee,
- feeOrders,
- desiredMakerAssetFillAmount,
- {
- value: ethValue,
- from: takerAddress,
- },
- );
- // Fetch end balances and construct expected outputs
- const takerEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(takerAddress);
- const forwarderEthBalance = await web3Wrapper.getBalanceInWeiAsync(forwarderContract.address);
- const newBalances = await erc20Wrapper.getBalancesAsync();
- const primaryTakerAssetFillAmount = ethValue;
- const totalEthSpent = primaryTakerAssetFillAmount.plus(gasPrice.times(tx.gasUsed));
- // Validate test case
- expect(makerAssetFillAmount).to.be.bignumber.greaterThan(desiredMakerAssetFillAmount);
- expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent));
- expect(newBalances[makerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount),
- );
- expect(newBalances[takerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultMakerAssetAddress].plus(makerAssetFillAmount),
- );
- expect(newBalances[makerAddress][weth.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][weth.address].plus(primaryTakerAssetFillAmount),
- );
- expect(newBalances[forwarderContract.address][weth.address]).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(newBalances[forwarderContract.address][defaultMakerAssetAddress]).to.be.bignumber.equal(
- constants.ZERO_AMOUNT,
- );
- expect(forwarderEthBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- });
- it('Should buy slightly greater MakerAsset when exchange rate is rounded, and MakerAsset is ZRX', async () => {
- // See the test case above for a detailed description of this case.
- // The difference here is that the MakerAsset is ZRX. We expect the same result as above,
- // but this tests a different code path.
- //
- // Construct test case using values from example above
- orderWithoutFee = await orderFactory.newSignedOrderAsync({
- makerAssetAmount: new BigNumber('30'),
- takerAssetAmount: new BigNumber('20'),
- makerAssetData: zrxAssetData,
- takerAssetData: assetDataUtils.encodeERC20AssetData(weth.address),
- makerFee: new BigNumber(0),
- takerFee: new BigNumber(0),
- });
- const ordersWithoutFee = [orderWithoutFee];
- const feeOrders: SignedOrder[] = [];
- const desiredMakerAssetFillAmount = new BigNumber('5');
- const makerAssetFillAmount = new BigNumber('6');
- const ethValue = new BigNumber('4');
- // Execute test case
- tx = await forwarderWrapper.marketBuyOrdersWithEthAsync(
- ordersWithoutFee,
- feeOrders,
- desiredMakerAssetFillAmount,
- {
- value: ethValue,
- from: takerAddress,
- },
- );
- // Fetch end balances and construct expected outputs
- const takerEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(takerAddress);
- const forwarderEthBalance = await web3Wrapper.getBalanceInWeiAsync(forwarderContract.address);
- const newBalances = await erc20Wrapper.getBalancesAsync();
- const primaryTakerAssetFillAmount = ethValue;
- const totalEthSpent = primaryTakerAssetFillAmount.plus(gasPrice.times(tx.gasUsed));
- // Validate test case
- expect(makerAssetFillAmount).to.be.bignumber.greaterThan(desiredMakerAssetFillAmount);
- expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent));
- expect(newBalances[makerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][zrxToken.address].minus(makerAssetFillAmount),
- );
- expect(newBalances[takerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[takerAddress][zrxToken.address].plus(makerAssetFillAmount),
- );
- expect(newBalances[makerAddress][weth.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][weth.address].plus(primaryTakerAssetFillAmount),
- );
- expect(newBalances[forwarderContract.address][weth.address]).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(forwarderEthBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- });
- it('Should buy slightly greater MakerAsset when exchange rate is rounded (Regression Test)', async () => {
- // Order taken from a transaction on mainnet that failed due to a rounding error.
- orderWithoutFee = await orderFactory.newSignedOrderAsync({
- makerAssetAmount: new BigNumber('268166666666666666666'),
- takerAssetAmount: new BigNumber('219090625878836371'),
- makerAssetData: assetDataUtils.encodeERC20AssetData(erc20TokenA.address),
- takerAssetData: assetDataUtils.encodeERC20AssetData(weth.address),
- makerFee: new BigNumber(0),
- takerFee: new BigNumber(0),
- });
- const ordersWithoutFee = [orderWithoutFee];
- const feeOrders: SignedOrder[] = [];
- // The taker will receive more than the desired amount of makerAsset due to rounding
- const desiredMakerAssetFillAmount = new BigNumber('5000000000000000000');
- const ethValue = new BigNumber('4084971271824171');
- const makerAssetFillAmount = ethValue
- .times(orderWithoutFee.makerAssetAmount)
- .dividedToIntegerBy(orderWithoutFee.takerAssetAmount);
- // Execute test case
- tx = await forwarderWrapper.marketBuyOrdersWithEthAsync(
- ordersWithoutFee,
- feeOrders,
- desiredMakerAssetFillAmount,
- {
- value: ethValue,
- from: takerAddress,
- },
- );
- // Fetch end balances and construct expected outputs
- const takerEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(takerAddress);
- const forwarderEthBalance = await web3Wrapper.getBalanceInWeiAsync(forwarderContract.address);
- const newBalances = await erc20Wrapper.getBalancesAsync();
- const primaryTakerAssetFillAmount = ethValue;
- const totalEthSpent = primaryTakerAssetFillAmount.plus(gasPrice.times(tx.gasUsed));
- // Validate test case
- expect(makerAssetFillAmount).to.be.bignumber.greaterThan(desiredMakerAssetFillAmount);
- expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent));
- expect(newBalances[makerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount),
- );
- expect(newBalances[takerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultMakerAssetAddress].plus(makerAssetFillAmount),
- );
- expect(newBalances[makerAddress][weth.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][weth.address].plus(primaryTakerAssetFillAmount),
- );
- expect(newBalances[forwarderContract.address][weth.address]).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(newBalances[forwarderContract.address][defaultMakerAssetAddress]).to.be.bignumber.equal(
- constants.ZERO_AMOUNT,
- );
- expect(forwarderEthBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- });
- it('Should buy slightly greater MakerAsset when exchange rate is rounded, and MakerAsset is ZRX (Regression Test)', async () => {
- // Order taken from a transaction on mainnet that failed due to a rounding error.
- orderWithoutFee = await orderFactory.newSignedOrderAsync({
- makerAssetAmount: new BigNumber('268166666666666666666'),
- takerAssetAmount: new BigNumber('219090625878836371'),
- makerAssetData: zrxAssetData,
- takerAssetData: assetDataUtils.encodeERC20AssetData(weth.address),
- makerFee: new BigNumber(0),
- takerFee: new BigNumber(0),
- });
- const ordersWithoutFee = [orderWithoutFee];
- const feeOrders: SignedOrder[] = [];
- // The taker will receive more than the desired amount of makerAsset due to rounding
- const desiredMakerAssetFillAmount = new BigNumber('5000000000000000000');
- const ethValue = new BigNumber('4084971271824171');
- const makerAssetFillAmount = ethValue
- .times(orderWithoutFee.makerAssetAmount)
- .dividedToIntegerBy(orderWithoutFee.takerAssetAmount);
- // Execute test case
- tx = await forwarderWrapper.marketBuyOrdersWithEthAsync(
- ordersWithoutFee,
- feeOrders,
- desiredMakerAssetFillAmount,
- {
- value: ethValue,
- from: takerAddress,
- },
- );
- // Fetch end balances and construct expected outputs
- const takerEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(takerAddress);
- const forwarderEthBalance = await web3Wrapper.getBalanceInWeiAsync(forwarderContract.address);
- const newBalances = await erc20Wrapper.getBalancesAsync();
- const primaryTakerAssetFillAmount = ethValue;
- const totalEthSpent = primaryTakerAssetFillAmount.plus(gasPrice.times(tx.gasUsed));
- // Validate test case
- expect(makerAssetFillAmount).to.be.bignumber.greaterThan(desiredMakerAssetFillAmount);
- expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent));
- expect(newBalances[makerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][zrxToken.address].minus(makerAssetFillAmount),
- );
- expect(newBalances[takerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[takerAddress][zrxToken.address].plus(makerAssetFillAmount),
- );
- expect(newBalances[makerAddress][weth.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][weth.address].plus(primaryTakerAssetFillAmount),
- );
- expect(newBalances[forwarderContract.address][weth.address]).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(forwarderEthBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- });
- it('Should buy correct MakerAsset when exchange rate is NOT rounded, and MakerAsset is ZRX (Regression Test)', async () => {
- // An extra unit of TakerAsset was sent to the exchange contract to account for rounding errors, in Forwarder v1.
- // Specifically, the takerFillAmount was calculated using Floor(desiredMakerAmount * exchangeRate) + 1
- // We have since changed this to be Ceil(desiredMakerAmount * exchangeRate)
- // These calculations produce different results when `desiredMakerAmount * exchangeRate` is an integer.
- //
- // This test verifies that `ceil` is sufficient:
- // Let TakerAssetAmount = MakerAssetAmount * 2
- // -> exchangeRate = TakerAssetAmount / MakerAssetAmount = (2*MakerAssetAmount)/MakerAssetAmount = 2
- // .: desiredMakerAmount * exchangeRate is an integer.
- //
- // Construct test case using values from example above
- orderWithoutFee = await orderFactory.newSignedOrderAsync({
- makerAssetAmount: new BigNumber('30'),
- takerAssetAmount: new BigNumber('60'),
- makerAssetData: zrxAssetData,
- takerAssetData: assetDataUtils.encodeERC20AssetData(weth.address),
- makerFee: new BigNumber(0),
- takerFee: new BigNumber(0),
- });
- const ordersWithoutFee = [orderWithoutFee];
- const feeOrders: SignedOrder[] = [];
- const makerAssetFillAmount = new BigNumber('5');
- const ethValue = new BigNumber('10');
- // Execute test case
- tx = await forwarderWrapper.marketBuyOrdersWithEthAsync(ordersWithoutFee, feeOrders, makerAssetFillAmount, {
- value: ethValue,
- from: takerAddress,
- });
- // Fetch end balances and construct expected outputs
- const takerEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(takerAddress);
- const forwarderEthBalance = await web3Wrapper.getBalanceInWeiAsync(forwarderContract.address);
- const newBalances = await erc20Wrapper.getBalancesAsync();
- const primaryTakerAssetFillAmount = ethValue;
- const totalEthSpent = primaryTakerAssetFillAmount.plus(gasPrice.times(tx.gasUsed));
- // Validate test case
- expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent));
- expect(newBalances[makerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][zrxToken.address].minus(makerAssetFillAmount),
- );
- expect(newBalances[takerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[takerAddress][zrxToken.address].plus(makerAssetFillAmount),
- );
- expect(newBalances[makerAddress][weth.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][weth.address].plus(primaryTakerAssetFillAmount),
- );
- expect(newBalances[forwarderContract.address][weth.address]).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(forwarderEthBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- });
- });
- describe('marketBuyOrdersWithEth with extra fees', () => {
- it('should buy an asset and send fee to feeRecipient', async () => {
- const ordersWithoutFee = [orderWithoutFee];
- const feeOrders: SignedOrder[] = [];
- const makerAssetFillAmount = orderWithoutFee.makerAssetAmount.dividedToIntegerBy(2);
- const ethValue = orderWithoutFee.takerAssetAmount;
-
- const baseFeePercentage = 2;
- feePercentage = ForwarderWrapper.getPercentageOfValue(constants.PERCENTAGE_DENOMINATOR, baseFeePercentage);
- const feeRecipientEthBalanceBefore = await web3Wrapper.getBalanceInWeiAsync(feeRecipientAddress);
- tx = await forwarderWrapper.marketBuyOrdersWithEthAsync(
- ordersWithoutFee,
- feeOrders,
- makerAssetFillAmount,
- {
- value: ethValue,
- from: takerAddress,
- },
- { feePercentage, feeRecipient: feeRecipientAddress },
- );
- const takerEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(takerAddress);
- const forwarderEthBalance = await web3Wrapper.getBalanceInWeiAsync(forwarderContract.address);
- const feeRecipientEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(feeRecipientAddress);
- const newBalances = await erc20Wrapper.getBalancesAsync();
-
- const primaryTakerAssetFillAmount = orderWithoutFee.takerAssetAmount.dividedToIntegerBy(2);
- const ethSpentOnFee = ForwarderWrapper.getPercentageOfValue(primaryTakerAssetFillAmount, baseFeePercentage);
- const totalEthSpent = primaryTakerAssetFillAmount.plus(ethSpentOnFee).plus(gasPrice.times(tx.gasUsed));
-
- expect(feeRecipientEthBalanceAfter).to.be.bignumber.equal(feeRecipientEthBalanceBefore.plus(ethSpentOnFee));
- expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent));
- expect(newBalances[makerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount),
- );
- expect(newBalances[takerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultMakerAssetAddress].plus(makerAssetFillAmount),
- );
- expect(newBalances[makerAddress][weth.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][weth.address].plus(primaryTakerAssetFillAmount),
- );
- expect(newBalances[forwarderContract.address][weth.address]).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(newBalances[forwarderContract.address][defaultMakerAssetAddress]).to.be.bignumber.equal(
- constants.ZERO_AMOUNT,
- );
- expect(forwarderEthBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- });
- it('should fail if the fee is set too high', async () => {
- const ordersWithoutFee = [orderWithoutFee];
- const feeOrders: SignedOrder[] = [];
- const makerAssetFillAmount = orderWithoutFee.makerAssetAmount.dividedToIntegerBy(2);
- const ethValue = orderWithoutFee.takerAssetAmount;
-
- const baseFeePercentage = 6;
- feePercentage = ForwarderWrapper.getPercentageOfValue(constants.PERCENTAGE_DENOMINATOR, baseFeePercentage);
- await expectTransactionFailedAsync(
- forwarderWrapper.marketBuyOrdersWithEthAsync(
- ordersWithoutFee,
- feeOrders,
- makerAssetFillAmount,
- {
- value: ethValue,
- from: takerAddress,
- },
- { feePercentage, feeRecipient: feeRecipientAddress },
- ),
- RevertReason.FeePercentageTooLarge,
- );
- });
- it('should fail if there is not enough ETH remaining to pay the fee', async () => {
- const ordersWithoutFee = [orderWithoutFee];
- const feeOrders: SignedOrder[] = [];
- const makerAssetFillAmount = orderWithoutFee.makerAssetAmount.dividedToIntegerBy(2);
- const ethValue = orderWithoutFee.takerAssetAmount.dividedToIntegerBy(2);
-
- const baseFeePercentage = 2;
- feePercentage = ForwarderWrapper.getPercentageOfValue(constants.PERCENTAGE_DENOMINATOR, baseFeePercentage);
- await expectTransactionFailedAsync(
- forwarderWrapper.marketBuyOrdersWithEthAsync(
- ordersWithoutFee,
- feeOrders,
- makerAssetFillAmount,
- {
- value: ethValue,
- from: takerAddress,
- },
- { feePercentage, feeRecipient: feeRecipientAddress },
- ),
- RevertReason.InsufficientEthRemaining,
- );
- });
- });
- describe('withdrawAsset', () => {
- it('should allow owner to withdraw ERC20 tokens', async () => {
- const zrxWithdrawAmount = erc20Balances[forwarderContract.address][zrxToken.address];
- await forwarderWrapper.withdrawAssetAsync(zrxAssetData, zrxWithdrawAmount, { from: owner });
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(newBalances[owner][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[owner][zrxToken.address].plus(zrxWithdrawAmount),
- );
- expect(newBalances[forwarderContract.address][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[forwarderContract.address][zrxToken.address].minus(zrxWithdrawAmount),
- );
- });
- it('should revert if not called by owner', async () => {
- const zrxWithdrawAmount = erc20Balances[forwarderContract.address][zrxToken.address];
- await expectTransactionFailedAsync(
- forwarderWrapper.withdrawAssetAsync(zrxAssetData, zrxWithdrawAmount, { from: makerAddress }),
- RevertReason.OnlyContractOwner,
- );
- });
- });
-});
-// tslint:disable:max-file-line-count
-// tslint:enable:no-unnecessary-type-assertion
diff --git a/contracts/extensions/test/extensions/order_matcher.ts b/contracts/extensions/test/extensions/order_matcher.ts
deleted file mode 100644
index acb46ced4..000000000
--- a/contracts/extensions/test/extensions/order_matcher.ts
+++ /dev/null
@@ -1,818 +0,0 @@
-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/extensions/test/extensions/order_validator.ts b/contracts/extensions/test/extensions/order_validator.ts
deleted file mode 100644
index 7d8675f36..000000000
--- a/contracts/extensions/test/extensions/order_validator.ts
+++ /dev/null
@@ -1,609 +0,0 @@
-import {
- artifacts as protocolArtifacts,
- ERC20ProxyContract,
- ERC20Wrapper,
- ERC721ProxyContract,
- ERC721Wrapper,
- ExchangeContract,
- ExchangeWrapper,
-} from '@0x/contracts-protocol';
-import {
- chaiSetup,
- constants,
- OrderFactory,
- OrderStatus,
- provider,
- txDefaults,
- web3Wrapper,
-} from '@0x/contracts-test-utils';
-import { DummyERC20TokenContract, DummyERC721TokenContract } from '@0x/contracts-tokens';
-import { BlockchainLifecycle } from '@0x/dev-utils';
-import { assetDataUtils, orderHashUtils } from '@0x/order-utils';
-import { SignedOrder } from '@0x/types';
-import { BigNumber } from '@0x/utils';
-import * as chai from 'chai';
-import * as _ from 'lodash';
-
-import { OrderValidatorContract } from '../../generated-wrappers/order_validator';
-import { artifacts } from '../../src/artifacts/index';
-
-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(
- protocolArtifacts.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 0 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(constants.ZERO_AMOUNT);
- });
- });
- });
- 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,
- );
- const isApproved = true;
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc721Token.setApprovalForAll.sendTransactionAsync(erc721Proxy.address, isApproved, {
- 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,
- );
- const isApproved = true;
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc721Token.setApprovalForAll.sendTransactionAsync(erc721Proxy.address, isApproved, {
- 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,
- );
- const isApproved = true;
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc721Token.setApprovalForAll.sendTransactionAsync(erc721Proxy.address, isApproved, {
- 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/contracts/extensions/test/global_hooks.ts b/contracts/extensions/test/global_hooks.ts
deleted file mode 100644
index f8ace376a..000000000
--- a/contracts/extensions/test/global_hooks.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-import { env, EnvVars } from '@0x/dev-utils';
-
-import { coverage, profiler, provider } from '@0x/contracts-test-utils';
-before('start web3 provider', () => {
- provider.start();
-});
-after('generate coverage report', async () => {
- if (env.parseBoolean(EnvVars.SolidityCoverage)) {
- const coverageSubprovider = coverage.getCoverageSubproviderSingleton();
- await coverageSubprovider.writeCoverageAsync();
- }
- if (env.parseBoolean(EnvVars.SolidityProfiler)) {
- const profilerSubprovider = profiler.getProfilerSubproviderSingleton();
- await profilerSubprovider.writeProfilerOutputAsync();
- }
- provider.stop();
-});
diff --git a/contracts/extensions/test/utils/balance_threshold_wrapper.ts b/contracts/extensions/test/utils/balance_threshold_wrapper.ts
deleted file mode 100644
index 28a4ef011..000000000
--- a/contracts/extensions/test/utils/balance_threshold_wrapper.ts
+++ /dev/null
@@ -1,283 +0,0 @@
-import { artifacts as protocolArtifacts, ExchangeContract } from '@0x/contracts-protocol';
-import {
- FillResults,
- formatters,
- LogDecoder,
- OrderInfo,
- orderUtils,
- TransactionFactory,
-} from '@0x/contracts-test-utils';
-import { artifacts as tokensArtifacts } from '@0x/contracts-tokens';
-import { SignedOrder } from '@0x/types';
-import { BigNumber } from '@0x/utils';
-import { Web3Wrapper } from '@0x/web3-wrapper';
-import { Provider, TransactionReceiptWithDecodedLogs } from 'ethereum-types';
-import * as _ from 'lodash';
-
-import { BalanceThresholdFilterContract } from '../../generated-wrappers/balance_threshold_filter';
-import { artifacts } from '../../src/artifacts';
-
-export class BalanceThresholdWrapper {
- private readonly _balanceThresholdFilter: BalanceThresholdFilterContract;
- private readonly _signerTransactionFactory: TransactionFactory;
- private readonly _exchange: ExchangeContract;
- private readonly _web3Wrapper: Web3Wrapper;
- private readonly _logDecoder: LogDecoder;
- constructor(
- balanceThresholdFilter: BalanceThresholdFilterContract,
- exchangeContract: ExchangeContract,
- signerTransactionFactory: TransactionFactory,
- provider: Provider,
- ) {
- this._balanceThresholdFilter = balanceThresholdFilter;
- this._exchange = exchangeContract;
- this._signerTransactionFactory = signerTransactionFactory;
- this._web3Wrapper = new Web3Wrapper(provider);
- this._logDecoder = new LogDecoder(this._web3Wrapper, {
- ...artifacts,
- ...tokensArtifacts,
- ...protocolArtifacts,
- });
- }
- public async fillOrderAsync(
- signedOrder: SignedOrder,
- from: string,
- opts: { takerAssetFillAmount?: BigNumber } = {},
- ): Promise<TransactionReceiptWithDecodedLogs> {
- const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount);
- const data = this._exchange.fillOrder.getABIEncodedTransactionData(
- params.order,
- params.takerAssetFillAmount,
- params.signature,
- );
- const txReceipt = this._executeTransactionAsync(data, from);
- return txReceipt;
- }
- public async fillOrKillOrderAsync(
- signedOrder: SignedOrder,
- from: string,
- opts: { takerAssetFillAmount?: BigNumber } = {},
- ): Promise<TransactionReceiptWithDecodedLogs> {
- const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount);
- const data = this._exchange.fillOrKillOrder.getABIEncodedTransactionData(
- params.order,
- params.takerAssetFillAmount,
- params.signature,
- );
- const txReceipt = this._executeTransactionAsync(data, from);
- return txReceipt;
- }
- public async fillOrderNoThrowAsync(
- signedOrder: SignedOrder,
- from: string,
- opts: { takerAssetFillAmount?: BigNumber; gas?: number } = {},
- ): Promise<TransactionReceiptWithDecodedLogs> {
- const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount);
- const data = this._exchange.fillOrderNoThrow.getABIEncodedTransactionData(
- params.order,
- params.takerAssetFillAmount,
- params.signature,
- );
- const txReceipt = this._executeTransactionAsync(data, from, opts.gas);
- return txReceipt;
- }
- public async batchFillOrdersAsync(
- orders: SignedOrder[],
- from: string,
- opts: { takerAssetFillAmounts?: BigNumber[] } = {},
- ): Promise<TransactionReceiptWithDecodedLogs> {
- const params = formatters.createBatchFill(orders, opts.takerAssetFillAmounts);
- const data = this._exchange.batchFillOrders.getABIEncodedTransactionData(
- params.orders,
- params.takerAssetFillAmounts,
- params.signatures,
- );
- const txReceipt = this._executeTransactionAsync(data, from);
- return txReceipt;
- }
- public async batchFillOrKillOrdersAsync(
- orders: SignedOrder[],
- from: string,
- opts: { takerAssetFillAmounts?: BigNumber[] } = {},
- ): Promise<TransactionReceiptWithDecodedLogs> {
- const params = formatters.createBatchFill(orders, opts.takerAssetFillAmounts);
- const data = this._exchange.batchFillOrKillOrders.getABIEncodedTransactionData(
- params.orders,
- params.takerAssetFillAmounts,
- params.signatures,
- );
- const txReceipt = this._executeTransactionAsync(data, from);
- return txReceipt;
- }
- public async batchFillOrdersNoThrowAsync(
- orders: SignedOrder[],
- from: string,
- opts: { takerAssetFillAmounts?: BigNumber[]; gas?: number } = {},
- ): Promise<TransactionReceiptWithDecodedLogs> {
- const params = formatters.createBatchFill(orders, opts.takerAssetFillAmounts);
- const data = this._exchange.batchFillOrKillOrders.getABIEncodedTransactionData(
- params.orders,
- params.takerAssetFillAmounts,
- params.signatures,
- );
- const txReceipt = this._executeTransactionAsync(data, from, opts.gas);
- return txReceipt;
- }
- public async marketSellOrdersAsync(
- orders: SignedOrder[],
- from: string,
- opts: { takerAssetFillAmount: BigNumber },
- ): Promise<TransactionReceiptWithDecodedLogs> {
- const params = formatters.createMarketSellOrders(orders, opts.takerAssetFillAmount);
- const data = this._exchange.marketSellOrders.getABIEncodedTransactionData(
- params.orders,
- params.takerAssetFillAmount,
- params.signatures,
- );
- const txReceipt = this._executeTransactionAsync(data, from);
- return txReceipt;
- }
- public async marketSellOrdersNoThrowAsync(
- orders: SignedOrder[],
- from: string,
- opts: { takerAssetFillAmount: BigNumber; gas?: number },
- ): Promise<TransactionReceiptWithDecodedLogs> {
- const params = formatters.createMarketSellOrders(orders, opts.takerAssetFillAmount);
- const data = this._exchange.marketSellOrdersNoThrow.getABIEncodedTransactionData(
- params.orders,
- params.takerAssetFillAmount,
- params.signatures,
- );
- const txReceipt = this._executeTransactionAsync(data, from, opts.gas);
- return txReceipt;
- }
- public async marketBuyOrdersAsync(
- orders: SignedOrder[],
- from: string,
- opts: { makerAssetFillAmount: BigNumber },
- ): Promise<TransactionReceiptWithDecodedLogs> {
- const params = formatters.createMarketBuyOrders(orders, opts.makerAssetFillAmount);
- const data = this._exchange.marketBuyOrders.getABIEncodedTransactionData(
- params.orders,
- params.makerAssetFillAmount,
- params.signatures,
- );
- const txReceipt = this._executeTransactionAsync(data, from);
- return txReceipt;
- }
- public async marketBuyOrdersNoThrowAsync(
- orders: SignedOrder[],
- from: string,
- opts: { makerAssetFillAmount: BigNumber; gas?: number },
- ): Promise<TransactionReceiptWithDecodedLogs> {
- const params = formatters.createMarketBuyOrders(orders, opts.makerAssetFillAmount);
- const data = this._exchange.marketBuyOrdersNoThrow.getABIEncodedTransactionData(
- params.orders,
- params.makerAssetFillAmount,
- params.signatures,
- );
- const txReceipt = this._executeTransactionAsync(data, from, opts.gas);
- return txReceipt;
- }
- public async cancelOrderAsync(signedOrder: SignedOrder, from: string): Promise<TransactionReceiptWithDecodedLogs> {
- const params = orderUtils.createCancel(signedOrder);
- const data = this._exchange.cancelOrder.getABIEncodedTransactionData(params.order);
- const txReceipt = this._executeTransactionAsync(data, from);
- return txReceipt;
- }
- public async batchCancelOrdersAsync(
- orders: SignedOrder[],
- from: string,
- ): Promise<TransactionReceiptWithDecodedLogs> {
- const params = formatters.createBatchCancel(orders);
- const data = this._exchange.batchCancelOrders.getABIEncodedTransactionData(params.orders);
- const txReceipt = this._executeTransactionAsync(data, from);
- return txReceipt;
- }
- public async cancelOrdersUpToAsync(salt: BigNumber, from: string): Promise<TransactionReceiptWithDecodedLogs> {
- const data = this._exchange.cancelOrdersUpTo.getABIEncodedTransactionData(salt);
- const txReceipt = this._executeTransactionAsync(data, from);
- return txReceipt;
- }
- public async getTakerAssetFilledAmountAsync(orderHashHex: string): Promise<BigNumber> {
- const filledAmount = await this._exchange.filled.callAsync(orderHashHex);
- return filledAmount;
- }
- public async isCancelledAsync(orderHashHex: string): Promise<boolean> {
- const isCancelled = await this._exchange.cancelled.callAsync(orderHashHex);
- return isCancelled;
- }
- public async getOrderEpochAsync(makerAddress: string, senderAddress: string): Promise<BigNumber> {
- const orderEpoch = await this._exchange.orderEpoch.callAsync(makerAddress, senderAddress);
- return orderEpoch;
- }
- public async getOrderInfoAsync(signedOrder: SignedOrder): Promise<OrderInfo> {
- const orderInfo = await this._exchange.getOrderInfo.callAsync(signedOrder);
- return orderInfo;
- }
- public async getOrdersInfoAsync(signedOrders: SignedOrder[]): Promise<OrderInfo[]> {
- const ordersInfo = (await this._exchange.getOrdersInfo.callAsync(signedOrders)) as OrderInfo[];
- return ordersInfo;
- }
- public async matchOrdersAsync(
- signedOrderLeft: SignedOrder,
- signedOrderRight: SignedOrder,
- from: string,
- ): Promise<TransactionReceiptWithDecodedLogs> {
- const params = orderUtils.createMatchOrders(signedOrderLeft, signedOrderRight);
- const data = await this._exchange.matchOrders.getABIEncodedTransactionData(
- params.left,
- params.right,
- params.leftSignature,
- params.rightSignature,
- );
- const txReceipt = this._executeTransactionAsync(data, from);
- return txReceipt;
- }
- public async getFillOrderResultsAsync(
- signedOrder: SignedOrder,
- from: string,
- opts: { takerAssetFillAmount?: BigNumber } = {},
- ): Promise<FillResults> {
- const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount);
- const fillResults = await this._exchange.fillOrder.callAsync(
- params.order,
- params.takerAssetFillAmount,
- params.signature,
- { from },
- );
- return fillResults;
- }
- public abiEncodeFillOrder(signedOrder: SignedOrder, opts: { takerAssetFillAmount?: BigNumber } = {}): string {
- const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount);
- const data = this._exchange.fillOrder.getABIEncodedTransactionData(
- params.order,
- params.takerAssetFillAmount,
- params.signature,
- );
- return data;
- }
- public getBalanceThresholdAddress(): string {
- return this._balanceThresholdFilter.address;
- }
- public getExchangeAddress(): string {
- return this._exchange.address;
- }
- private async _executeTransactionAsync(
- abiEncodedExchangeTxData: string,
- from: string,
- gas?: number,
- ): Promise<TransactionReceiptWithDecodedLogs> {
- const signedExchangeTx = this._signerTransactionFactory.newSignedTransaction(abiEncodedExchangeTxData);
- const txOpts = _.isUndefined(gas) ? { from } : { from, gas };
- const txHash = await this._balanceThresholdFilter.executeTransaction.sendTransactionAsync(
- signedExchangeTx.salt,
- signedExchangeTx.signerAddress,
- signedExchangeTx.data,
- signedExchangeTx.signature,
- txOpts,
- );
- const txReceipt = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
- return txReceipt;
- }
-}
diff --git a/contracts/extensions/test/utils/dutch_auction_test_wrapper.ts b/contracts/extensions/test/utils/dutch_auction_test_wrapper.ts
deleted file mode 100644
index c1e2f2070..000000000
--- a/contracts/extensions/test/utils/dutch_auction_test_wrapper.ts
+++ /dev/null
@@ -1,62 +0,0 @@
-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/test/utils/forwarder_wrapper.ts b/contracts/extensions/test/utils/forwarder_wrapper.ts
deleted file mode 100644
index 4a43be04a..000000000
--- a/contracts/extensions/test/utils/forwarder_wrapper.ts
+++ /dev/null
@@ -1,124 +0,0 @@
-import { artifacts as protocolArtifacts } from '@0x/contracts-protocol';
-import { constants, formatters, LogDecoder, MarketSellOrders } from '@0x/contracts-test-utils';
-import { artifacts as tokensArtifacts } from '@0x/contracts-tokens';
-import { SignedOrder } from '@0x/types';
-import { BigNumber } from '@0x/utils';
-import { Web3Wrapper } from '@0x/web3-wrapper';
-import { Provider, TransactionReceiptWithDecodedLogs, TxDataPayable } from 'ethereum-types';
-import * as _ from 'lodash';
-
-import { ForwarderContract } from '../../generated-wrappers/forwarder';
-import { artifacts } from '../../src/artifacts';
-
-export class ForwarderWrapper {
- private readonly _web3Wrapper: Web3Wrapper;
- private readonly _forwarderContract: ForwarderContract;
- private readonly _logDecoder: LogDecoder;
- public static getPercentageOfValue(value: BigNumber, percentage: number): BigNumber {
- const numerator = constants.PERCENTAGE_DENOMINATOR.times(percentage).dividedToIntegerBy(100);
- const newValue = value.times(numerator).dividedToIntegerBy(constants.PERCENTAGE_DENOMINATOR);
- return newValue;
- }
- public static getWethForFeeOrders(feeAmount: BigNumber, feeOrders: SignedOrder[]): BigNumber {
- let wethAmount = new BigNumber(0);
- let remainingFeeAmount = feeAmount;
- _.forEach(feeOrders, feeOrder => {
- const feeAvailable = feeOrder.makerAssetAmount.minus(feeOrder.takerFee);
- if (!remainingFeeAmount.isZero() && feeAvailable.gt(remainingFeeAmount)) {
- wethAmount = wethAmount.plus(
- feeOrder.takerAssetAmount
- .times(remainingFeeAmount)
- .dividedBy(feeAvailable)
- .integerValue(BigNumber.ROUND_CEIL),
- );
- remainingFeeAmount = new BigNumber(0);
- } else if (!remainingFeeAmount.isZero()) {
- wethAmount = wethAmount.plus(feeOrder.takerAssetAmount);
- remainingFeeAmount = remainingFeeAmount.minus(feeAvailable);
- }
- });
- return wethAmount;
- }
- private static _createOptimizedOrders(signedOrders: SignedOrder[]): MarketSellOrders {
- _.forEach(signedOrders, (signedOrder, index) => {
- signedOrder.takerAssetData = constants.NULL_BYTES;
- if (index > 0) {
- signedOrder.makerAssetData = constants.NULL_BYTES;
- }
- });
- const params = formatters.createMarketSellOrders(signedOrders, constants.ZERO_AMOUNT);
- return params;
- }
- private static _createOptimizedZrxOrders(signedOrders: SignedOrder[]): MarketSellOrders {
- _.forEach(signedOrders, signedOrder => {
- signedOrder.makerAssetData = constants.NULL_BYTES;
- signedOrder.takerAssetData = constants.NULL_BYTES;
- });
- const params = formatters.createMarketSellOrders(signedOrders, constants.ZERO_AMOUNT);
- return params;
- }
- constructor(contractInstance: ForwarderContract, provider: Provider) {
- this._forwarderContract = contractInstance;
- this._web3Wrapper = new Web3Wrapper(provider);
- this._logDecoder = new LogDecoder(this._web3Wrapper, {
- ...artifacts,
- ...tokensArtifacts,
- ...protocolArtifacts,
- });
- }
- public async marketSellOrdersWithEthAsync(
- orders: SignedOrder[],
- feeOrders: SignedOrder[],
- txData: TxDataPayable,
- opts: { feePercentage?: BigNumber; feeRecipient?: string } = {},
- ): Promise<TransactionReceiptWithDecodedLogs> {
- const params = ForwarderWrapper._createOptimizedOrders(orders);
- const feeParams = ForwarderWrapper._createOptimizedZrxOrders(feeOrders);
- const feePercentage = _.isUndefined(opts.feePercentage) ? constants.ZERO_AMOUNT : opts.feePercentage;
- const feeRecipient = _.isUndefined(opts.feeRecipient) ? constants.NULL_ADDRESS : opts.feeRecipient;
- const txHash = await this._forwarderContract.marketSellOrdersWithEth.sendTransactionAsync(
- params.orders,
- params.signatures,
- feeParams.orders,
- feeParams.signatures,
- feePercentage,
- feeRecipient,
- txData,
- );
- const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
- return tx;
- }
- public async marketBuyOrdersWithEthAsync(
- orders: SignedOrder[],
- feeOrders: SignedOrder[],
- makerAssetFillAmount: BigNumber,
- txData: TxDataPayable,
- opts: { feePercentage?: BigNumber; feeRecipient?: string } = {},
- ): Promise<TransactionReceiptWithDecodedLogs> {
- const params = ForwarderWrapper._createOptimizedOrders(orders);
- const feeParams = ForwarderWrapper._createOptimizedZrxOrders(feeOrders);
- const feePercentage = _.isUndefined(opts.feePercentage) ? constants.ZERO_AMOUNT : opts.feePercentage;
- const feeRecipient = _.isUndefined(opts.feeRecipient) ? constants.NULL_ADDRESS : opts.feeRecipient;
- const txHash = await this._forwarderContract.marketBuyOrdersWithEth.sendTransactionAsync(
- params.orders,
- makerAssetFillAmount,
- params.signatures,
- feeParams.orders,
- feeParams.signatures,
- feePercentage,
- feeRecipient,
- txData,
- );
- const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
- return tx;
- }
- public async withdrawAssetAsync(
- assetData: string,
- amount: BigNumber,
- txData: TxDataPayable,
- ): Promise<TransactionReceiptWithDecodedLogs> {
- const txHash = await this._forwarderContract.withdrawAsset.sendTransactionAsync(assetData, amount, txData);
- const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
- return tx;
- }
-}
diff --git a/contracts/extensions/tsconfig.json b/contracts/extensions/tsconfig.json
deleted file mode 100644
index ed9b4fbe1..000000000
--- a/contracts/extensions/tsconfig.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "extends": "../../tsconfig",
- "compilerOptions": {
- "outDir": "lib",
- "rootDir": ".",
- "resolveJsonModule": true
- },
- "include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"],
- "files": [
- "./generated-artifacts/BalanceThresholdFilter.json",
- "./generated-artifacts/DutchAuction.json",
- "./generated-artifacts/Forwarder.json",
- "./generated-artifacts/OrderMatcher.json",
- "./generated-artifacts/OrderValidator.json"
- ],
- "exclude": ["./deploy/solc/solc_bin"]
-}
diff --git a/contracts/extensions/tslint.json b/contracts/extensions/tslint.json
deleted file mode 100644
index 1bb3ac2a2..000000000
--- a/contracts/extensions/tslint.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "extends": ["@0x/tslint-config"],
- "rules": {
- "custom-no-magic-numbers": false
- }
-}