aboutsummaryrefslogtreecommitdiffstats
path: root/packages
diff options
context:
space:
mode:
authorLeonid Logvinov <logvinov.leon@gmail.com>2018-11-22 21:52:25 +0800
committerLeonid Logvinov <logvinov.leon@gmail.com>2018-12-03 18:31:53 +0800
commit4668b0732ce4b62b3b7d19ea4e155a6d3c4e6004 (patch)
tree43cad9046ecc4c9e59e9d9743c6f076878881037 /packages
parent502e9c7be48caafd7725451789f896efdaf17dac (diff)
downloaddexon-0x-contracts-4668b0732ce4b62b3b7d19ea4e155a6d3c4e6004.tar.gz
dexon-0x-contracts-4668b0732ce4b62b3b7d19ea4e155a6d3c4e6004.tar.zst
dexon-0x-contracts-4668b0732ce4b62b3b7d19ea4e155a6d3c4e6004.zip
Move packages/contracts to contracts/core
Diffstat (limited to 'packages')
-rw-r--r--packages/contracts/.solhint.json20
-rw-r--r--packages/contracts/.solhintignore3
-rw-r--r--packages/contracts/CHANGELOG.json135
-rw-r--r--packages/contracts/README.md129
-rw-r--r--packages/contracts/compiler.json60
-rw-r--r--packages/contracts/contracts/examples/ExchangeWrapper/ExchangeWrapper.sol100
-rw-r--r--packages/contracts/contracts/examples/Validator/Validator.sol56
-rw-r--r--packages/contracts/contracts/examples/Wallet/Wallet.sol65
-rw-r--r--packages/contracts/contracts/examples/Whitelist/Whitelist.sol136
-rw-r--r--packages/contracts/contracts/extensions/Forwarder/Forwarder.sol50
-rw-r--r--packages/contracts/contracts/extensions/Forwarder/MixinAssets.sol143
-rw-r--r--packages/contracts/contracts/extensions/Forwarder/MixinExchangeWrapper.sol260
-rw-r--r--packages/contracts/contracts/extensions/Forwarder/MixinForwarderCore.sol214
-rw-r--r--packages/contracts/contracts/extensions/Forwarder/MixinWeth.sol113
-rw-r--r--packages/contracts/contracts/extensions/Forwarder/interfaces/IAssets.sol34
-rw-r--r--packages/contracts/contracts/extensions/Forwarder/interfaces/IForwarder.sol30
-rw-r--r--packages/contracts/contracts/extensions/Forwarder/interfaces/IForwarderCore.sol80
-rw-r--r--packages/contracts/contracts/extensions/Forwarder/libs/LibConstants.sol62
-rw-r--r--packages/contracts/contracts/extensions/Forwarder/libs/LibForwarderErrors.sol34
-rw-r--r--packages/contracts/contracts/extensions/Forwarder/mixins/MAssets.sol53
-rw-r--r--packages/contracts/contracts/extensions/Forwarder/mixins/MExchangeWrapper.sol87
-rw-r--r--packages/contracts/contracts/extensions/Forwarder/mixins/MWeth.sol41
-rw-r--r--packages/contracts/contracts/extensions/OrderValidator/OrderValidator.sol218
-rw-r--r--packages/contracts/contracts/multisig/MultiSigWallet.sol393
-rw-r--r--packages/contracts/contracts/multisig/MultiSigWalletWithTimeLock.sol127
-rw-r--r--packages/contracts/contracts/protocol/AssetProxy/ERC20Proxy.sol184
-rw-r--r--packages/contracts/contracts/protocol/AssetProxy/ERC721Proxy.sol171
-rw-r--r--packages/contracts/contracts/protocol/AssetProxy/MixinAuthorizable.sol117
-rw-r--r--packages/contracts/contracts/protocol/AssetProxy/interfaces/IAssetData.sol44
-rw-r--r--packages/contracts/contracts/protocol/AssetProxy/interfaces/IAssetProxy.sol46
-rw-r--r--packages/contracts/contracts/protocol/AssetProxy/interfaces/IAuthorizable.sol52
-rw-r--r--packages/contracts/contracts/protocol/AssetProxy/libs/LibAssetProxyErrors.sol38
-rw-r--r--packages/contracts/contracts/protocol/AssetProxy/mixins/MAuthorizable.sol41
-rw-r--r--packages/contracts/contracts/protocol/AssetProxyOwner/AssetProxyOwner.sol108
-rw-r--r--packages/contracts/contracts/protocol/Exchange/Exchange.sol53
-rw-r--r--packages/contracts/contracts/protocol/Exchange/MixinAssetProxyDispatcher.sol174
-rw-r--r--packages/contracts/contracts/protocol/Exchange/MixinExchangeCore.sol529
-rw-r--r--packages/contracts/contracts/protocol/Exchange/MixinMatchOrders.sol335
-rw-r--r--packages/contracts/contracts/protocol/Exchange/MixinSignatureValidator.sol324
-rw-r--r--packages/contracts/contracts/protocol/Exchange/MixinTransactions.sol152
-rw-r--r--packages/contracts/contracts/protocol/Exchange/MixinWrapperFunctions.sol426
-rw-r--r--packages/contracts/contracts/protocol/Exchange/interfaces/IAssetProxyDispatcher.sol37
-rw-r--r--packages/contracts/contracts/protocol/Exchange/interfaces/IExchange.sol38
-rw-r--r--packages/contracts/contracts/protocol/Exchange/interfaces/IExchangeCore.sol60
-rw-r--r--packages/contracts/contracts/protocol/Exchange/interfaces/IMatchOrders.sol44
-rw-r--r--packages/contracts/contracts/protocol/Exchange/interfaces/ISignatureValidator.sol57
-rw-r--r--packages/contracts/contracts/protocol/Exchange/interfaces/ITransactions.sol35
-rw-r--r--packages/contracts/contracts/protocol/Exchange/interfaces/IValidator.sol37
-rw-r--r--packages/contracts/contracts/protocol/Exchange/interfaces/IWallet.sol35
-rw-r--r--packages/contracts/contracts/protocol/Exchange/interfaces/IWrapperFunctions.sol160
-rw-r--r--packages/contracts/contracts/protocol/Exchange/libs/LibAbiEncoder.sol215
-rw-r--r--packages/contracts/contracts/protocol/Exchange/libs/LibConstants.sol49
-rw-r--r--packages/contracts/contracts/protocol/Exchange/libs/LibEIP712.sol87
-rw-r--r--packages/contracts/contracts/protocol/Exchange/libs/LibExchangeErrors.sol70
-rw-r--r--packages/contracts/contracts/protocol/Exchange/libs/LibFillResults.sol53
-rw-r--r--packages/contracts/contracts/protocol/Exchange/libs/LibMath.sol253
-rw-r--r--packages/contracts/contracts/protocol/Exchange/libs/LibOrder.sol145
-rw-r--r--packages/contracts/contracts/protocol/Exchange/mixins/MAssetProxyDispatcher.sol45
-rw-r--r--packages/contracts/contracts/protocol/Exchange/mixins/MExchangeCore.sol157
-rw-r--r--packages/contracts/contracts/protocol/Exchange/mixins/MMatchOrders.sol58
-rw-r--r--packages/contracts/contracts/protocol/Exchange/mixins/MSignatureValidator.sol75
-rw-r--r--packages/contracts/contracts/protocol/Exchange/mixins/MTransactions.sol58
-rw-r--r--packages/contracts/contracts/protocol/Exchange/mixins/MWrapperFunctions.sol41
-rw-r--r--packages/contracts/contracts/test/DummyERC20Token/DummyERC20Token.sol77
-rw-r--r--packages/contracts/contracts/test/DummyERC20Token/DummyMultipleReturnERC20Token.sol69
-rw-r--r--packages/contracts/contracts/test/DummyERC20Token/DummyNoReturnERC20Token.sol115
-rw-r--r--packages/contracts/contracts/test/DummyERC721Receiver/DummyERC721Receiver.sol67
-rw-r--r--packages/contracts/contracts/test/DummyERC721Receiver/InvalidERC721Receiver.sol66
-rw-r--r--packages/contracts/contracts/test/DummyERC721Token/DummyERC721Token.sol63
-rw-r--r--packages/contracts/contracts/test/ReentrantERC20Token/ReentrantERC20Token.sol188
-rw-r--r--packages/contracts/contracts/test/TestAssetProxyDispatcher/TestAssetProxyDispatcher.sol37
-rw-r--r--packages/contracts/contracts/test/TestAssetProxyOwner/TestAssetProxyOwner.sol58
-rw-r--r--packages/contracts/contracts/test/TestConstants/TestConstants.sol57
-rw-r--r--packages/contracts/contracts/test/TestExchangeInternals/TestExchangeInternals.sol191
-rw-r--r--packages/contracts/contracts/test/TestLibBytes/TestLibBytes.sol269
-rw-r--r--packages/contracts/contracts/test/TestLibs/TestLibs.sol152
-rw-r--r--packages/contracts/contracts/test/TestSignatureValidator/TestSignatureValidator.sol45
-rw-r--r--packages/contracts/contracts/test/TestStaticCallReceiver/TestStaticCallReceiver.sol81
-rw-r--r--packages/contracts/contracts/tokens/ERC20Token/ERC20Token.sol148
-rw-r--r--packages/contracts/contracts/tokens/ERC20Token/IERC20Token.sol87
-rw-r--r--packages/contracts/contracts/tokens/ERC20Token/MintableERC20Token.sol60
-rw-r--r--packages/contracts/contracts/tokens/ERC20Token/UnlimitedAllowanceERC20Token.sol70
-rw-r--r--packages/contracts/contracts/tokens/ERC721Token/ERC721Token.sol277
-rw-r--r--packages/contracts/contracts/tokens/ERC721Token/IERC721Receiver.sol44
-rw-r--r--packages/contracts/contracts/tokens/ERC721Token/IERC721Token.sol158
-rw-r--r--packages/contracts/contracts/tokens/ERC721Token/MintableERC721Token.sol82
-rw-r--r--packages/contracts/contracts/tokens/EtherToken/IEtherToken.sol33
-rw-r--r--packages/contracts/contracts/tokens/EtherToken/WETH9.sol758
-rw-r--r--packages/contracts/contracts/tokens/ZRXToken/ERC20Token_v1.sol44
-rw-r--r--packages/contracts/contracts/tokens/ZRXToken/Token_v1.sol39
-rw-r--r--packages/contracts/contracts/tokens/ZRXToken/UnlimitedAllowanceToken_v1.sol52
-rw-r--r--packages/contracts/contracts/tokens/ZRXToken/ZRXToken.sol41
-rw-r--r--packages/contracts/contracts/utils/LibBytes/LibBytes.sol567
-rw-r--r--packages/contracts/contracts/utils/Ownable/IOwnable.sol8
-rw-r--r--packages/contracts/contracts/utils/Ownable/Ownable.sol33
-rw-r--r--packages/contracts/contracts/utils/ReentrancyGuard/ReentrancyGuard.sol45
-rw-r--r--packages/contracts/contracts/utils/SafeMath/SafeMath.sol87
-rw-r--r--packages/contracts/package.json94
-rw-r--r--packages/contracts/src/artifacts/index.ts81
-rw-r--r--packages/contracts/src/wrappers/index.ts34
-rw-r--r--packages/contracts/test/asset_proxy/authorizable.ts207
-rw-r--r--packages/contracts/test/asset_proxy/proxies.ts1246
-rw-r--r--packages/contracts/test/exchange/core.ts1168
-rw-r--r--packages/contracts/test/exchange/dispatcher.ts280
-rw-r--r--packages/contracts/test/exchange/fill_order.ts312
-rw-r--r--packages/contracts/test/exchange/internal.ts466
-rw-r--r--packages/contracts/test/exchange/libs.ts137
-rw-r--r--packages/contracts/test/exchange/match_orders.ts1276
-rw-r--r--packages/contracts/test/exchange/signature_validator.ts522
-rw-r--r--packages/contracts/test/exchange/transactions.ts462
-rw-r--r--packages/contracts/test/exchange/wrapper.ts1452
-rw-r--r--packages/contracts/test/extensions/forwarder.ts1282
-rw-r--r--packages/contracts/test/extensions/order_validator.ts603
-rw-r--r--packages/contracts/test/global_hooks.ts15
-rw-r--r--packages/contracts/test/libraries/lib_bytes.ts871
-rw-r--r--packages/contracts/test/multisig/asset_proxy_owner.ts498
-rw-r--r--packages/contracts/test/multisig/multi_sig_with_time_lock.ts347
-rw-r--r--packages/contracts/test/tokens/erc721_token.ts279
-rw-r--r--packages/contracts/test/tokens/unlimited_allowance_token.ts191
-rw-r--r--packages/contracts/test/tokens/weth9.ts138
-rw-r--r--packages/contracts/test/tokens/zrx_token.ts206
-rw-r--r--packages/contracts/test/tutorials/arbitrage.ts260
-rw-r--r--packages/contracts/test/utils/abstract_asset_wrapper.ts3
-rw-r--r--packages/contracts/test/utils/address_utils.ts11
-rw-r--r--packages/contracts/test/utils/assertions.ts199
-rw-r--r--packages/contracts/test/utils/asset_wrapper.ts223
-rw-r--r--packages/contracts/test/utils/block_timestamp.ts43
-rw-r--r--packages/contracts/test/utils/chai_setup.ts13
-rw-r--r--packages/contracts/test/utils/combinatorial_utils.ts113
-rw-r--r--packages/contracts/test/utils/constants.ts67
-rw-r--r--packages/contracts/test/utils/coverage.ts21
-rw-r--r--packages/contracts/test/utils/erc20_wrapper.ts182
-rw-r--r--packages/contracts/test/utils/erc721_wrapper.ts239
-rw-r--r--packages/contracts/test/utils/exchange_wrapper.ts276
-rw-r--r--packages/contracts/test/utils/fill_order_combinatorial_utils.ts924
-rw-r--r--packages/contracts/test/utils/formatters.ts68
-rw-r--r--packages/contracts/test/utils/forwarder_wrapper.ts121
-rw-r--r--packages/contracts/test/utils/log_decoder.ts53
-rw-r--r--packages/contracts/test/utils/match_order_tester.ts566
-rw-r--r--packages/contracts/test/utils/multi_sig_wrapper.ts67
-rw-r--r--packages/contracts/test/utils/order_factory.ts38
-rw-r--r--packages/contracts/test/utils/order_factory_from_scenario.ts296
-rw-r--r--packages/contracts/test/utils/order_utils.ts58
-rw-r--r--packages/contracts/test/utils/profiler.ts27
-rw-r--r--packages/contracts/test/utils/revert_trace.ts21
-rw-r--r--packages/contracts/test/utils/signing_utils.ts29
-rw-r--r--packages/contracts/test/utils/simple_asset_balance_and_proxy_allowance_fetcher.ts19
-rw-r--r--packages/contracts/test/utils/simple_order_filled_cancelled_fetcher.ts31
-rw-r--r--packages/contracts/test/utils/test_with_reference.ts139
-rw-r--r--packages/contracts/test/utils/transaction_factory.ts37
-rw-r--r--packages/contracts/test/utils/type_encoding_utils.ts21
-rw-r--r--packages/contracts/test/utils/types.ts241
-rw-r--r--packages/contracts/test/utils/web3_wrapper.ts84
-rw-r--r--packages/contracts/test/utils_test/test_with_reference.ts63
-rw-r--r--packages/contracts/tsconfig.json49
-rw-r--r--packages/contracts/tslint.json6
156 files changed, 0 insertions, 28189 deletions
diff --git a/packages/contracts/.solhint.json b/packages/contracts/.solhint.json
deleted file mode 100644
index 076afe9f3..000000000
--- a/packages/contracts/.solhint.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "extends": "default",
- "rules": {
- "avoid-low-level-calls": false,
- "avoid-tx-origin": "warn",
- "bracket-align": false,
- "code-complexity": false,
- "const-name-snakecase": "error",
- "expression-indent": "error",
- "function-max-lines": false,
- "func-order": "error",
- "indent": ["error", 4],
- "max-line-length": ["warn", 160],
- "no-inline-assembly": false,
- "quotes": ["error", "double"],
- "separate-by-one-line-in-contract": "error",
- "space-after-comma": "error",
- "statement-indent": "error"
- }
-}
diff --git a/packages/contracts/.solhintignore b/packages/contracts/.solhintignore
deleted file mode 100644
index 1e33ec53b..000000000
--- a/packages/contracts/.solhintignore
+++ /dev/null
@@ -1,3 +0,0 @@
-contracts/tokens/ZRXToken/ERC20Token_v1.sol
-contracts/tokens/ZRXToken/Token_v1.sol
-contracts/tokens/ZRXToken/UnlimitedAllowanceToken_v1.sol
diff --git a/packages/contracts/CHANGELOG.json b/packages/contracts/CHANGELOG.json
deleted file mode 100644
index 7dfa06990..000000000
--- a/packages/contracts/CHANGELOG.json
+++ /dev/null
@@ -1,135 +0,0 @@
-[
- {
- "name": "MultiAssetProxy",
- "version": "1.0.0",
- "changes": [
- {
- "note": "Add MultiAssetProxy implementation",
- "pr": 1224
- }
- ]
- },
- {
- "name": "OrderValidator",
- "version": "1.0.1",
- "changes": [
- {
- "note": "remove `getApproved` check from ERC721 approval query",
- "pr": 1149
- }
- ]
- },
- {
- "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"
- }
- }
- ]
- },
- {
- "name": "OrderValidator",
- "version": "1.0.0",
- "changes": [
- {
- "note": "protocol v2 deploy",
- "networks": {
- "1": "0x9463e518dea6810309563c81d5266c1b1d149138",
- "3": "0x90431a90516ab49af23a0530e04e8c7836e7122f",
- "42": "0xb389da3d204b412df2f75c6afb3d0a7ce0bc283d"
- }
- }
- ]
- },
- {
- "name": "Exchange",
- "version": "2.0.0",
- "changes": [
- {
- "note": "protocol v2 deploy",
- "networks": {
- "1": "0x4f833a24e1f95d70f028921e27040ca56e09ab0b",
- "3": "0x4530c0483a1633c7a1c97d2c53721caff2caaaaf",
- "42": "0x35dd2932454449b14cee11a94d3674a936d5d7b2"
- }
- }
- ]
- },
- {
- "name": "ERC20Proxy",
- "version": "1.0.0",
- "changes": [
- {
- "note": "protocol v2 deploy",
- "networks": {
- "1": "0x2240dab907db71e64d3e0dba4800c83b5c502d4e",
- "3": "0xb1408f4c245a23c31b98d2c626777d4c0d766caa",
- "42": "0xf1ec01d6236d3cd881a0bf0130ea25fe4234003e"
- }
- }
- ]
- },
- {
- "name": "ERC721Proxy",
- "version": "1.0.0",
- "changes": [
- {
- "note": "protocol v2 deploy",
- "networks": {
- "1": "0x208e41fb445f1bb1b6780d58356e81405f3e6127",
- "3": "0xe654aac058bfbf9f83fcaee7793311dd82f6ddb4",
- "42": "0x2a9127c745688a165106c11cd4d647d2220af821"
- }
- }
- ]
- },
- {
- "name": "AssetProxyOwner",
- "version": "1.0.0",
- "changes": [
- {
- "note": "protocol v2 deploy",
- "networks": {
- "1": "0x17992e4ffb22730138e4b62aaa6367fa9d3699a6",
- "3": "0xf5fa5b5fed2727a0e44ac67f6772e97977aa358b",
- "42": "0x2c824d2882baa668e0d5202b1e7f2922278703f8"
- }
- }
- ]
- },
- {
- "name": "ZRXToken",
- "version": "1.0.0",
- "changes": [
- {
- "note": "protocol v1 deploy",
- "networks": {
- "1": "0xe41d2489571d322189246dafa5ebde1f4699f498",
- "3": "0xff67881f8d12f372d91baae9752eb3631ff0ed00",
- "42": "0x2002d3812f58e35f0ea1ffbf80a75a38c32175fa"
- }
- }
- ]
- }
-]
diff --git a/packages/contracts/README.md b/packages/contracts/README.md
deleted file mode 100644
index 97a2816ff..000000000
--- a/packages/contracts/README.md
+++ /dev/null
@@ -1,129 +0,0 @@
-## Contracts
-
-Smart contracts that implement the 0x protocol. Addresses of the deployed contracts can be found in the 0x [wiki](https://0xproject.com/wiki#Deployed-Addresses) or the [CHANGELOG](./CHANGELOG.json) of this package.
-
-## Usage
-
-Contracts that make up and interact with version 2.0.0 of the protocol can be found in the [contracts](./contracts) directory. The contents of this directory are broken down into the following subdirectories:
-
-* [protocol](./contracts/protocol)
- * This directory contains the contracts that make up version 2.0.0. A full specification can be found [here](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md).
-* [extensions](./contracts/extensions)
- * 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.
-* [examples](./contracts/examples)
- * This directory contains example implementations of contracts that interact with the protocol but are _not_ intended for use in production. Examples include [filter](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#filter-contracts) contracts, a [Wallet](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#wallet) contract, and a [Validator](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#validator) contract, among others.
-* [tokens](./contracts/tokens)
- * This directory contains implementations of different tokens and token standards, including [wETH](https://weth.io/), ZRX, [ERC20](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md), and [ERC721](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md).
-* [multisig](./contracts/multisig)
- * This directory contains the [Gnosis MultiSigWallet](https://github.com/gnosis/MultiSigWallet) and a custom extension that adds a timelock to transactions within the MultiSigWallet.
-* [utils](./contracts/utils)
- * This directory contains libraries and utils that are shared across all of the other directories.
-* [test](./contracts/test)
- * This directory contains mocks and other contracts that are used solely for testing contracts within the other directories.
-
-## 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=contracts yarn build
-```
-
-Or continuously rebuild on change:
-
-```bash
-PKG=contracts yarn watch
-```
-
-### Clean
-
-```bash
-yarn clean
-```
-
-### Lint
-
-```bash
-yarn lint
-```
-
-### Run Tests
-
-```bash
-yarn test
-```
-
-#### Testing options
-
-###### Revert stack traces
-
-If you want to see helpful stack traces (incl. line number, code snippet) for smart contract reverts, run the tests with:
-
-```
-yarn test:trace
-```
-
-**Note:** This currently slows down the test runs and is therefore not enabled by default.
-
-###### Backing Ethereum node
-
-By default, our tests run against an in-process [Ganache](https://github.com/trufflesuite/ganache-core) instance. In order to run the tests against [Geth](https://github.com/ethereum/go-ethereum), first follow the instructions in the README for the devnet package to start the devnet Geth node. Then run:
-
-```bash
-TEST_PROVIDER=geth yarn test
-```
-
-###### Code coverage
-
-In order to see the Solidity code coverage output generated by `@0x/sol-cov`, run:
-
-```
-yarn test:coverage
-```
-
-###### Gas profiler
-
-In order to profile the gas costs for a specific smart contract call/transaction, you can run the tests in `profiler` mode.
-
-**Note:** Traces emitted by ganache have incorrect gas costs so we recommend using Geth for profiling.
-
-```
-TEST_PROVIDER=geth yarn test:profiler
-```
-
-You'll see a warning that you need to explicitly enable and disable the profiler before and after the block of code you want to profile.
-
-```typescript
-import { profiler } from './utils/profiler';
-profiler.start();
-// Some call to a smart contract
-profiler.stop();
-```
-
-Without explicitly starting and stopping the profiler, the profiler output will be too busy, and therefore unusable.
diff --git a/packages/contracts/compiler.json b/packages/contracts/compiler.json
deleted file mode 100644
index c824e4645..000000000
--- a/packages/contracts/compiler.json
+++ /dev/null
@@ -1,60 +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": [
- "AssetProxyOwner",
- "DummyERC20Token",
- "DummyERC721Receiver",
- "DummyERC721Token",
- "DummyMultipleReturnERC20Token",
- "DummyNoReturnERC20Token",
- "ERC20Proxy",
- "ERC20Token",
- "ERC721Token",
- "ERC721Proxy",
- "Exchange",
- "ExchangeWrapper",
- "Forwarder",
- "IAssetData",
- "IAssetProxy",
- "InvalidERC721Receiver",
- "IValidator",
- "IWallet",
- "MixinAuthorizable",
- "MultiAssetProxy",
- "MultiSigWallet",
- "MultiSigWalletWithTimeLock",
- "OrderValidator",
- "ReentrantERC20Token",
- "TestAssetProxyOwner",
- "TestAssetProxyDispatcher",
- "TestConstants",
- "TestLibBytes",
- "TestLibs",
- "TestExchangeInternals",
- "TestSignatureValidator",
- "TestStaticCallReceiver",
- "Validator",
- "Wallet",
- "WETH9",
- "Whitelist",
- "ZRXToken"
- ]
-}
diff --git a/packages/contracts/contracts/examples/ExchangeWrapper/ExchangeWrapper.sol b/packages/contracts/contracts/examples/ExchangeWrapper/ExchangeWrapper.sol
deleted file mode 100644
index 2fa0e3c5e..000000000
--- a/packages/contracts/contracts/examples/ExchangeWrapper/ExchangeWrapper.sol
+++ /dev/null
@@ -1,100 +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 "../../protocol/Exchange/interfaces/IExchange.sol";
-import "../../protocol/Exchange/libs/LibOrder.sol";
-
-
-contract ExchangeWrapper {
-
- // Exchange contract.
- // solhint-disable-next-line var-name-mixedcase
- IExchange internal EXCHANGE;
-
- constructor (address _exchange)
- public
- {
- EXCHANGE = IExchange(_exchange);
- }
-
- /// @dev Cancels all orders created by sender with a salt less than or equal to the targetOrderEpoch
- /// and senderAddress equal to this contract.
- /// @param targetOrderEpoch Orders created with a salt less or equal to this value will be cancelled.
- /// @param salt Arbitrary value to gaurantee uniqueness of 0x transaction hash.
- /// @param makerSignature Proof that maker wishes to call this function with given params.
- function cancelOrdersUpTo(
- uint256 targetOrderEpoch,
- uint256 salt,
- bytes makerSignature
- )
- external
- {
- address makerAddress = msg.sender;
-
- // Encode arguments into byte array.
- bytes memory data = abi.encodeWithSelector(
- EXCHANGE.cancelOrdersUpTo.selector,
- targetOrderEpoch
- );
-
- // Call `cancelOrdersUpTo` via `executeTransaction`.
- EXCHANGE.executeTransaction(
- salt,
- makerAddress,
- data,
- makerSignature
- );
- }
-
- /// @dev Fills an order using `msg.sender` as the taker.
- /// @param order Order struct containing order specifications.
- /// @param takerAssetFillAmount Desired amount of takerAsset to sell.
- /// @param salt Arbitrary value to gaurantee uniqueness of 0x transaction hash.
- /// @param orderSignature Proof that order has been created by maker.
- /// @param takerSignature Proof that taker wishes to call this function with given params.
- function fillOrder(
- LibOrder.Order memory order,
- uint256 takerAssetFillAmount,
- uint256 salt,
- bytes memory orderSignature,
- bytes memory takerSignature
- )
- public
- {
- address takerAddress = msg.sender;
-
- // Encode arguments into byte array.
- bytes memory data = abi.encodeWithSelector(
- EXCHANGE.fillOrder.selector,
- order,
- takerAssetFillAmount,
- orderSignature
- );
-
- // Call `fillOrder` via `executeTransaction`.
- EXCHANGE.executeTransaction(
- salt,
- takerAddress,
- data,
- takerSignature
- );
- }
-}
diff --git a/packages/contracts/contracts/examples/Validator/Validator.sol b/packages/contracts/contracts/examples/Validator/Validator.sol
deleted file mode 100644
index 72ed528ba..000000000
--- a/packages/contracts/contracts/examples/Validator/Validator.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 "../../protocol/Exchange/interfaces/IValidator.sol";
-
-
-contract Validator is
- IValidator
-{
-
- // The single valid signer for this wallet.
- // solhint-disable-next-line var-name-mixedcase
- address internal VALID_SIGNER;
-
- /// @dev constructs a new `Validator` with a single valid signer.
- /// @param validSigner The sole, valid signer.
- constructor (address validSigner) public {
- VALID_SIGNER = validSigner;
- }
-
- /// @dev Verifies that a signature is valid. `signer` must match `VALID_SIGNER`.
- /// @param hash Message hash that is signed.
- /// @param signerAddress Address that should have signed the given hash.
- /// @param signature Proof of signing.
- /// @return Validity of signature.
- // solhint-disable no-unused-vars
- function isValidSignature(
- bytes32 hash,
- address signerAddress,
- bytes signature
- )
- external
- view
- returns (bool isValid)
- {
- return (signerAddress == VALID_SIGNER);
- }
- // solhint-enable no-unused-vars
-}
diff --git a/packages/contracts/contracts/examples/Wallet/Wallet.sol b/packages/contracts/contracts/examples/Wallet/Wallet.sol
deleted file mode 100644
index b75021a31..000000000
--- a/packages/contracts/contracts/examples/Wallet/Wallet.sol
+++ /dev/null
@@ -1,65 +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 "../../protocol/Exchange/interfaces/IWallet.sol";
-import "../../utils/LibBytes/LibBytes.sol";
-
-
-contract Wallet is
- IWallet
-{
- using LibBytes for bytes;
-
- // The owner of this wallet.
- // solhint-disable-next-line var-name-mixedcase
- address internal WALLET_OWNER;
-
- /// @dev constructs a new `Wallet` with a single owner.
- /// @param walletOwner The owner of this wallet.
- constructor (address walletOwner) public {
- WALLET_OWNER = walletOwner;
- }
-
- /// @dev Validates an EIP712 signature.
- /// The signer must match the owner of this wallet.
- /// @param hash Message hash that is signed.
- /// @param eip712Signature Proof of signing.
- /// @return Validity of signature.
- function isValidSignature(
- bytes32 hash,
- bytes eip712Signature
- )
- external
- view
- returns (bool isValid)
- {
- require(
- eip712Signature.length == 65,
- "LENGTH_65_REQUIRED"
- );
-
- uint8 v = uint8(eip712Signature[0]);
- bytes32 r = eip712Signature.readBytes32(1);
- bytes32 s = eip712Signature.readBytes32(33);
- address recoveredAddress = ecrecover(hash, v, r, s);
- isValid = WALLET_OWNER == recoveredAddress;
- return isValid;
- }
-}
diff --git a/packages/contracts/contracts/examples/Whitelist/Whitelist.sol b/packages/contracts/contracts/examples/Whitelist/Whitelist.sol
deleted file mode 100644
index e4e25038c..000000000
--- a/packages/contracts/contracts/examples/Whitelist/Whitelist.sol
+++ /dev/null
@@ -1,136 +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 "../../protocol/Exchange/interfaces/IExchange.sol";
-import "../../protocol/Exchange/libs/LibOrder.sol";
-import "../../utils/Ownable/Ownable.sol";
-
-
-contract Whitelist is
- Ownable
-{
-
- // Mapping of address => whitelist status.
- mapping (address => bool) public isWhitelisted;
-
- // Exchange contract.
- // solhint-disable var-name-mixedcase
- IExchange internal EXCHANGE;
- bytes internal TX_ORIGIN_SIGNATURE;
- // solhint-enable var-name-mixedcase
-
- byte constant internal VALIDATOR_SIGNATURE_BYTE = "\x05";
-
- constructor (address _exchange)
- public
- {
- EXCHANGE = IExchange(_exchange);
- TX_ORIGIN_SIGNATURE = abi.encodePacked(address(this), VALIDATOR_SIGNATURE_BYTE);
- }
-
- /// @dev Adds or removes an address from the whitelist.
- /// @param target Address to add or remove from whitelist.
- /// @param isApproved Whitelist status to assign to address.
- function updateWhitelistStatus(
- address target,
- bool isApproved
- )
- external
- onlyOwner
- {
- isWhitelisted[target] = isApproved;
- }
-
- /// @dev Verifies signer is same as signer of current Ethereum transaction.
- /// NOTE: This function can currently be used to validate signatures coming from outside of this contract.
- /// Extra safety checks can be added for a production contract.
- /// @param signerAddress Address that should have signed the given hash.
- /// @param signature Proof of signing.
- /// @return Validity of order signature.
- // solhint-disable no-unused-vars
- function isValidSignature(
- bytes32 hash,
- address signerAddress,
- bytes signature
- )
- external
- view
- returns (bool isValid)
- {
- // solhint-disable-next-line avoid-tx-origin
- return signerAddress == tx.origin;
- }
- // solhint-enable no-unused-vars
-
- /// @dev Fills an order using `msg.sender` as the taker.
- /// The transaction will revert if both the maker and taker are not whitelisted.
- /// Orders should specify this contract as the `senderAddress` in order to gaurantee
- /// that both maker and taker have been whitelisted.
- /// @param order Order struct containing order specifications.
- /// @param takerAssetFillAmount Desired amount of takerAsset to sell.
- /// @param salt Arbitrary value to gaurantee uniqueness of 0x transaction hash.
- /// @param orderSignature Proof that order has been created by maker.
- function fillOrderIfWhitelisted(
- LibOrder.Order memory order,
- uint256 takerAssetFillAmount,
- uint256 salt,
- bytes memory orderSignature
- )
- public
- {
- address takerAddress = msg.sender;
-
- // This contract must be the entry point for the transaction.
- require(
- // solhint-disable-next-line avoid-tx-origin
- takerAddress == tx.origin,
- "INVALID_SENDER"
- );
-
- // Check if maker is on the whitelist.
- require(
- isWhitelisted[order.makerAddress],
- "MAKER_NOT_WHITELISTED"
- );
-
- // Check if taker is on the whitelist.
- require(
- isWhitelisted[takerAddress],
- "TAKER_NOT_WHITELISTED"
- );
-
- // Encode arguments into byte array.
- bytes memory data = abi.encodeWithSelector(
- EXCHANGE.fillOrder.selector,
- order,
- takerAssetFillAmount,
- orderSignature
- );
-
- // Call `fillOrder` via `executeTransaction`.
- EXCHANGE.executeTransaction(
- salt,
- takerAddress,
- data,
- TX_ORIGIN_SIGNATURE
- );
- }
-}
diff --git a/packages/contracts/contracts/extensions/Forwarder/Forwarder.sol b/packages/contracts/contracts/extensions/Forwarder/Forwarder.sol
deleted file mode 100644
index 94dec40ed..000000000
--- a/packages/contracts/contracts/extensions/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/packages/contracts/contracts/extensions/Forwarder/MixinAssets.sol b/packages/contracts/contracts/extensions/Forwarder/MixinAssets.sol
deleted file mode 100644
index 43efb5ff3..000000000
--- a/packages/contracts/contracts/extensions/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 "../../utils/LibBytes/LibBytes.sol";
-import "../../utils/Ownable/Ownable.sol";
-import "../../tokens/ERC20Token/IERC20Token.sol";
-import "../../tokens/ERC721Token/IERC721Token.sol";
-import "./libs/LibConstants.sol";
-import "./mixins/MAssets.sol";
-
-
-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/packages/contracts/contracts/extensions/Forwarder/MixinExchangeWrapper.sol b/packages/contracts/contracts/extensions/Forwarder/MixinExchangeWrapper.sol
deleted file mode 100644
index 4991c0ea5..000000000
--- a/packages/contracts/contracts/extensions/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 "../../protocol/Exchange/libs/LibAbiEncoder.sol";
-import "../../protocol/Exchange/libs/LibOrder.sol";
-import "../../protocol/Exchange/libs/LibFillResults.sol";
-import "../../protocol/Exchange/libs/LibMath.sol";
-
-
-contract MixinExchangeWrapper is
- 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/packages/contracts/contracts/extensions/Forwarder/MixinForwarderCore.sol b/packages/contracts/contracts/extensions/Forwarder/MixinForwarderCore.sol
deleted file mode 100644
index 54487f726..000000000
--- a/packages/contracts/contracts/extensions/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 "../../utils/LibBytes/LibBytes.sol";
-import "../../protocol/Exchange/libs/LibOrder.sol";
-import "../../protocol/Exchange/libs/LibFillResults.sol";
-import "../../protocol/Exchange/libs/LibMath.sol";
-
-
-contract MixinForwarderCore is
- 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/packages/contracts/contracts/extensions/Forwarder/MixinWeth.sol b/packages/contracts/contracts/extensions/Forwarder/MixinWeth.sol
deleted file mode 100644
index d2814a49b..000000000
--- a/packages/contracts/contracts/extensions/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 "../../protocol/Exchange/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/packages/contracts/contracts/extensions/Forwarder/interfaces/IAssets.sol b/packages/contracts/contracts/extensions/Forwarder/interfaces/IAssets.sol
deleted file mode 100644
index 1e034c003..000000000
--- a/packages/contracts/contracts/extensions/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/packages/contracts/contracts/extensions/Forwarder/interfaces/IForwarder.sol b/packages/contracts/contracts/extensions/Forwarder/interfaces/IForwarder.sol
deleted file mode 100644
index f5a26e2ba..000000000
--- a/packages/contracts/contracts/extensions/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/packages/contracts/contracts/extensions/Forwarder/interfaces/IForwarderCore.sol b/packages/contracts/contracts/extensions/Forwarder/interfaces/IForwarderCore.sol
deleted file mode 100644
index 74c7da01d..000000000
--- a/packages/contracts/contracts/extensions/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 "../../../protocol/Exchange/libs/LibOrder.sol";
-import "../../../protocol/Exchange/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/packages/contracts/contracts/extensions/Forwarder/libs/LibConstants.sol b/packages/contracts/contracts/extensions/Forwarder/libs/LibConstants.sol
deleted file mode 100644
index 704e42ce3..000000000
--- a/packages/contracts/contracts/extensions/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 "../../../utils/LibBytes/LibBytes.sol";
-import "../../../protocol/Exchange/interfaces/IExchange.sol";
-import "../../../tokens/EtherToken/IEtherToken.sol";
-import "../../../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/packages/contracts/contracts/extensions/Forwarder/libs/LibForwarderErrors.sol b/packages/contracts/contracts/extensions/Forwarder/libs/LibForwarderErrors.sol
deleted file mode 100644
index fb3ade1db..000000000
--- a/packages/contracts/contracts/extensions/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/packages/contracts/contracts/extensions/Forwarder/mixins/MAssets.sol b/packages/contracts/contracts/extensions/Forwarder/mixins/MAssets.sol
deleted file mode 100644
index 9e7f80d97..000000000
--- a/packages/contracts/contracts/extensions/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/packages/contracts/contracts/extensions/Forwarder/mixins/MExchangeWrapper.sol b/packages/contracts/contracts/extensions/Forwarder/mixins/MExchangeWrapper.sol
deleted file mode 100644
index 13c26b03a..000000000
--- a/packages/contracts/contracts/extensions/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 "../../../protocol/Exchange/libs/LibOrder.sol";
-import "../../../protocol/Exchange/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/packages/contracts/contracts/extensions/Forwarder/mixins/MWeth.sol b/packages/contracts/contracts/extensions/Forwarder/mixins/MWeth.sol
deleted file mode 100644
index 88e77be4e..000000000
--- a/packages/contracts/contracts/extensions/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/packages/contracts/contracts/extensions/OrderValidator/OrderValidator.sol b/packages/contracts/contracts/extensions/OrderValidator/OrderValidator.sol
deleted file mode 100644
index 3385d35ef..000000000
--- a/packages/contracts/contracts/extensions/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 "../../protocol/Exchange/interfaces/IExchange.sol";
-import "../../protocol/Exchange/libs/LibOrder.sol";
-import "../../tokens/ERC20Token/IERC20Token.sol";
-import "../../tokens/ERC721Token/IERC721Token.sol";
-import "../../utils/LibBytes/LibBytes.sol";
-
-
-contract OrderValidator {
-
- 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/packages/contracts/contracts/multisig/MultiSigWallet.sol b/packages/contracts/contracts/multisig/MultiSigWallet.sol
deleted file mode 100644
index 516e7391c..000000000
--- a/packages/contracts/contracts/multisig/MultiSigWallet.sol
+++ /dev/null
@@ -1,393 +0,0 @@
-// solhint-disable
-pragma solidity ^0.4.15;
-
-
-/// @title Multisignature wallet - Allows multiple parties to agree on transactions before execution.
-/// @author Stefan George - <stefan.george@consensys.net>
-contract MultiSigWallet {
-
- /*
- * Events
- */
- event Confirmation(address indexed sender, uint indexed transactionId);
- event Revocation(address indexed sender, uint indexed transactionId);
- event Submission(uint indexed transactionId);
- event Execution(uint indexed transactionId);
- event ExecutionFailure(uint indexed transactionId);
- event Deposit(address indexed sender, uint value);
- event OwnerAddition(address indexed owner);
- event OwnerRemoval(address indexed owner);
- event RequirementChange(uint required);
-
- /*
- * Constants
- */
- uint constant public MAX_OWNER_COUNT = 50;
-
- /*
- * Storage
- */
- mapping (uint => Transaction) public transactions;
- mapping (uint => mapping (address => bool)) public confirmations;
- mapping (address => bool) public isOwner;
- address[] public owners;
- uint public required;
- uint public transactionCount;
-
- struct Transaction {
- address destination;
- uint value;
- bytes data;
- bool executed;
- }
-
- /*
- * Modifiers
- */
- modifier onlyWallet() {
- require(msg.sender == address(this));
- _;
- }
-
- modifier ownerDoesNotExist(address owner) {
- require(!isOwner[owner]);
- _;
- }
-
- modifier ownerExists(address owner) {
- require(isOwner[owner]);
- _;
- }
-
- modifier transactionExists(uint transactionId) {
- require(transactions[transactionId].destination != 0);
- _;
- }
-
- modifier confirmed(uint transactionId, address owner) {
- require(confirmations[transactionId][owner]);
- _;
- }
-
- modifier notConfirmed(uint transactionId, address owner) {
- require(!confirmations[transactionId][owner]);
- _;
- }
-
- modifier notExecuted(uint transactionId) {
- require(!transactions[transactionId].executed);
- _;
- }
-
- modifier notNull(address _address) {
- require(_address != 0);
- _;
- }
-
- modifier validRequirement(uint ownerCount, uint _required) {
- require(ownerCount <= MAX_OWNER_COUNT
- && _required <= ownerCount
- && _required != 0
- && ownerCount != 0);
- _;
- }
-
- /// @dev Fallback function allows to deposit ether.
- function()
- payable
- {
- if (msg.value > 0)
- Deposit(msg.sender, msg.value);
- }
-
- /*
- * Public functions
- */
- /// @dev Contract constructor sets initial owners and required number of confirmations.
- /// @param _owners List of initial owners.
- /// @param _required Number of required confirmations.
- function MultiSigWallet(address[] _owners, uint _required)
- public
- validRequirement(_owners.length, _required)
- {
- for (uint i=0; i<_owners.length; i++) {
- require(!isOwner[_owners[i]] && _owners[i] != 0);
- isOwner[_owners[i]] = true;
- }
- owners = _owners;
- required = _required;
- }
-
- /// @dev Allows to add a new owner. Transaction has to be sent by wallet.
- /// @param owner Address of new owner.
- function addOwner(address owner)
- public
- onlyWallet
- ownerDoesNotExist(owner)
- notNull(owner)
- validRequirement(owners.length + 1, required)
- {
- isOwner[owner] = true;
- owners.push(owner);
- OwnerAddition(owner);
- }
-
- /// @dev Allows to remove an owner. Transaction has to be sent by wallet.
- /// @param owner Address of owner.
- function removeOwner(address owner)
- public
- onlyWallet
- ownerExists(owner)
- {
- isOwner[owner] = false;
- for (uint i=0; i<owners.length - 1; i++)
- if (owners[i] == owner) {
- owners[i] = owners[owners.length - 1];
- break;
- }
- owners.length -= 1;
- if (required > owners.length)
- changeRequirement(owners.length);
- OwnerRemoval(owner);
- }
-
- /// @dev Allows to replace an owner with a new owner. Transaction has to be sent by wallet.
- /// @param owner Address of owner to be replaced.
- /// @param newOwner Address of new owner.
- function replaceOwner(address owner, address newOwner)
- public
- onlyWallet
- ownerExists(owner)
- ownerDoesNotExist(newOwner)
- {
- for (uint i=0; i<owners.length; i++)
- if (owners[i] == owner) {
- owners[i] = newOwner;
- break;
- }
- isOwner[owner] = false;
- isOwner[newOwner] = true;
- OwnerRemoval(owner);
- OwnerAddition(newOwner);
- }
-
- /// @dev Allows to change the number of required confirmations. Transaction has to be sent by wallet.
- /// @param _required Number of required confirmations.
- function changeRequirement(uint _required)
- public
- onlyWallet
- validRequirement(owners.length, _required)
- {
- required = _required;
- RequirementChange(_required);
- }
-
- /// @dev Allows an owner to submit and confirm a transaction.
- /// @param destination Transaction target address.
- /// @param value Transaction ether value.
- /// @param data Transaction data payload.
- /// @return Returns transaction ID.
- function submitTransaction(address destination, uint value, bytes data)
- public
- returns (uint transactionId)
- {
- transactionId = addTransaction(destination, value, data);
- confirmTransaction(transactionId);
- }
-
- /// @dev Allows an owner to confirm a transaction.
- /// @param transactionId Transaction ID.
- function confirmTransaction(uint transactionId)
- public
- ownerExists(msg.sender)
- transactionExists(transactionId)
- notConfirmed(transactionId, msg.sender)
- {
- confirmations[transactionId][msg.sender] = true;
- Confirmation(msg.sender, transactionId);
- executeTransaction(transactionId);
- }
-
- /// @dev Allows an owner to revoke a confirmation for a transaction.
- /// @param transactionId Transaction ID.
- function revokeConfirmation(uint transactionId)
- public
- ownerExists(msg.sender)
- confirmed(transactionId, msg.sender)
- notExecuted(transactionId)
- {
- confirmations[transactionId][msg.sender] = false;
- Revocation(msg.sender, transactionId);
- }
-
- /// @dev Allows anyone to execute a confirmed transaction.
- /// @param transactionId Transaction ID.
- function executeTransaction(uint transactionId)
- public
- ownerExists(msg.sender)
- confirmed(transactionId, msg.sender)
- notExecuted(transactionId)
- {
- if (isConfirmed(transactionId)) {
- Transaction storage txn = transactions[transactionId];
- txn.executed = true;
- if (external_call(txn.destination, txn.value, txn.data.length, txn.data))
- Execution(transactionId);
- else {
- ExecutionFailure(transactionId);
- txn.executed = false;
- }
- }
- }
-
- // call has been separated into its own function in order to take advantage
- // of the Solidity's code generator to produce a loop that copies tx.data into memory.
- function external_call(address destination, uint value, uint dataLength, bytes data) internal returns (bool) {
- bool result;
- assembly {
- let x := mload(0x40) // "Allocate" memory for output (0x40 is where "free memory" pointer is stored by convention)
- let d := add(data, 32) // First 32 bytes are the padded length of data, so exclude that
- result := call(
- sub(gas, 34710), // 34710 is the value that solidity is currently emitting
- // It includes callGas (700) + callVeryLow (3, to pay for SUB) + callValueTransferGas (9000) +
- // callNewAccountGas (25000, in case the destination address does not exist and needs creating)
- destination,
- value,
- d,
- dataLength, // Size of the input (in bytes) - this is what fixes the padding problem
- x,
- 0 // Output is ignored, therefore the output size is zero
- )
- }
- return result;
- }
-
- /// @dev Returns the confirmation status of a transaction.
- /// @param transactionId Transaction ID.
- /// @return Confirmation status.
- function isConfirmed(uint transactionId)
- public
- constant
- returns (bool)
- {
- uint count = 0;
- for (uint i=0; i<owners.length; i++) {
- if (confirmations[transactionId][owners[i]])
- count += 1;
- if (count == required)
- return true;
- }
- }
-
- /*
- * Internal functions
- */
- /// @dev Adds a new transaction to the transaction mapping, if transaction does not exist yet.
- /// @param destination Transaction target address.
- /// @param value Transaction ether value.
- /// @param data Transaction data payload.
- /// @return Returns transaction ID.
- function addTransaction(address destination, uint value, bytes data)
- internal
- notNull(destination)
- returns (uint transactionId)
- {
- transactionId = transactionCount;
- transactions[transactionId] = Transaction({
- destination: destination,
- value: value,
- data: data,
- executed: false
- });
- transactionCount += 1;
- Submission(transactionId);
- }
-
- /*
- * Web3 call functions
- */
- /// @dev Returns number of confirmations of a transaction.
- /// @param transactionId Transaction ID.
- /// @return Number of confirmations.
- function getConfirmationCount(uint transactionId)
- public
- constant
- returns (uint count)
- {
- for (uint i=0; i<owners.length; i++)
- if (confirmations[transactionId][owners[i]])
- count += 1;
- }
-
- /// @dev Returns total number of transactions after filers are applied.
- /// @param pending Include pending transactions.
- /// @param executed Include executed transactions.
- /// @return Total number of transactions after filters are applied.
- function getTransactionCount(bool pending, bool executed)
- public
- constant
- returns (uint count)
- {
- for (uint i=0; i<transactionCount; i++)
- if ( pending && !transactions[i].executed
- || executed && transactions[i].executed)
- count += 1;
- }
-
- /// @dev Returns list of owners.
- /// @return List of owner addresses.
- function getOwners()
- public
- constant
- returns (address[])
- {
- return owners;
- }
-
- /// @dev Returns array with owner addresses, which confirmed transaction.
- /// @param transactionId Transaction ID.
- /// @return Returns array of owner addresses.
- function getConfirmations(uint transactionId)
- public
- constant
- returns (address[] _confirmations)
- {
- address[] memory confirmationsTemp = new address[](owners.length);
- uint count = 0;
- uint i;
- for (i=0; i<owners.length; i++)
- if (confirmations[transactionId][owners[i]]) {
- confirmationsTemp[count] = owners[i];
- count += 1;
- }
- _confirmations = new address[](count);
- for (i=0; i<count; i++)
- _confirmations[i] = confirmationsTemp[i];
- }
-
- /// @dev Returns list of transaction IDs in defined range.
- /// @param from Index start position of transaction array.
- /// @param to Index end position of transaction array.
- /// @param pending Include pending transactions.
- /// @param executed Include executed transactions.
- /// @return Returns array of transaction IDs.
- function getTransactionIds(uint from, uint to, bool pending, bool executed)
- public
- constant
- returns (uint[] _transactionIds)
- {
- uint[] memory transactionIdsTemp = new uint[](transactionCount);
- uint count = 0;
- uint i;
- for (i=0; i<transactionCount; i++)
- if ( pending && !transactions[i].executed
- || executed && transactions[i].executed)
- {
- transactionIdsTemp[count] = i;
- count += 1;
- }
- _transactionIds = new uint[](to - from);
- for (i=from; i<to; i++)
- _transactionIds[i - from] = transactionIdsTemp[i];
- }
-} \ No newline at end of file
diff --git a/packages/contracts/contracts/multisig/MultiSigWalletWithTimeLock.sol b/packages/contracts/contracts/multisig/MultiSigWalletWithTimeLock.sol
deleted file mode 100644
index 9513d3b30..000000000
--- a/packages/contracts/contracts/multisig/MultiSigWalletWithTimeLock.sol
+++ /dev/null
@@ -1,127 +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 "./MultiSigWallet.sol";
-
-
-/// @title Multisignature wallet with time lock- Allows multiple parties to execute a transaction after a time lock has passed.
-/// @author Amir Bandeali - <amir@0xProject.com>
-// solhint-disable not-rely-on-time
-contract MultiSigWalletWithTimeLock is
- MultiSigWallet
-{
- event ConfirmationTimeSet(uint256 indexed transactionId, uint256 confirmationTime);
- event TimeLockChange(uint256 secondsTimeLocked);
-
- uint256 public secondsTimeLocked;
-
- mapping (uint256 => uint256) public confirmationTimes;
-
- modifier notFullyConfirmed(uint256 transactionId) {
- require(
- !isConfirmed(transactionId),
- "TX_FULLY_CONFIRMED"
- );
- _;
- }
-
- modifier fullyConfirmed(uint256 transactionId) {
- require(
- isConfirmed(transactionId),
- "TX_NOT_FULLY_CONFIRMED"
- );
- _;
- }
-
- modifier pastTimeLock(uint256 transactionId) {
- require(
- block.timestamp >= confirmationTimes[transactionId] + secondsTimeLocked,
- "TIME_LOCK_INCOMPLETE"
- );
- _;
- }
-
- /// @dev Contract constructor sets initial owners, required number of confirmations, and time lock.
- /// @param _owners List of initial owners.
- /// @param _required Number of required confirmations.
- /// @param _secondsTimeLocked Duration needed after a transaction is confirmed and before it becomes executable, in seconds.
- constructor (
- address[] _owners,
- uint256 _required,
- uint256 _secondsTimeLocked
- )
- public
- MultiSigWallet(_owners, _required)
- {
- secondsTimeLocked = _secondsTimeLocked;
- }
-
- /// @dev Changes the duration of the time lock for transactions.
- /// @param _secondsTimeLocked Duration needed after a transaction is confirmed and before it becomes executable, in seconds.
- function changeTimeLock(uint256 _secondsTimeLocked)
- public
- onlyWallet
- {
- secondsTimeLocked = _secondsTimeLocked;
- emit TimeLockChange(_secondsTimeLocked);
- }
-
- /// @dev Allows an owner to confirm a transaction.
- /// @param transactionId Transaction ID.
- function confirmTransaction(uint256 transactionId)
- public
- ownerExists(msg.sender)
- transactionExists(transactionId)
- notConfirmed(transactionId, msg.sender)
- notFullyConfirmed(transactionId)
- {
- confirmations[transactionId][msg.sender] = true;
- emit Confirmation(msg.sender, transactionId);
- if (isConfirmed(transactionId)) {
- setConfirmationTime(transactionId, block.timestamp);
- }
- }
-
- /// @dev Allows anyone to execute a confirmed transaction.
- /// @param transactionId Transaction ID.
- function executeTransaction(uint256 transactionId)
- public
- notExecuted(transactionId)
- fullyConfirmed(transactionId)
- pastTimeLock(transactionId)
- {
- Transaction storage txn = transactions[transactionId];
- txn.executed = true;
- if (external_call(txn.destination, txn.value, txn.data.length, txn.data)) {
- emit Execution(transactionId);
- } else {
- emit ExecutionFailure(transactionId);
- txn.executed = false;
- }
- }
-
- /// @dev Sets the time of when a submission first passed.
- function setConfirmationTime(uint256 transactionId, uint256 confirmationTime)
- internal
- {
- confirmationTimes[transactionId] = confirmationTime;
- emit ConfirmationTimeSet(transactionId, confirmationTime);
- }
-}
diff --git a/packages/contracts/contracts/protocol/AssetProxy/ERC20Proxy.sol b/packages/contracts/contracts/protocol/AssetProxy/ERC20Proxy.sol
deleted file mode 100644
index 258443bca..000000000
--- a/packages/contracts/contracts/protocol/AssetProxy/ERC20Proxy.sol
+++ /dev/null
@@ -1,184 +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 "./MixinAuthorizable.sol";
-
-
-contract ERC20Proxy is
- MixinAuthorizable
-{
- // Id of this proxy.
- bytes4 constant internal PROXY_ID = bytes4(keccak256("ERC20Token(address)"));
-
- // solhint-disable-next-line payable-fallback
- function ()
- external
- {
- assembly {
- // The first 4 bytes of calldata holds the function selector
- let selector := and(calldataload(0), 0xffffffff00000000000000000000000000000000000000000000000000000000)
-
- // `transferFrom` will be called with the following parameters:
- // assetData Encoded byte array.
- // from Address to transfer asset from.
- // to Address to transfer asset to.
- // amount Amount of asset to transfer.
- // bytes4(keccak256("transferFrom(bytes,address,address,uint256)")) = 0xa85e59e4
- if eq(selector, 0xa85e59e400000000000000000000000000000000000000000000000000000000) {
-
- // To lookup a value in a mapping, we load from the storage location keccak256(k, p),
- // where k is the key left padded to 32 bytes and p is the storage slot
- let start := mload(64)
- mstore(start, and(caller, 0xffffffffffffffffffffffffffffffffffffffff))
- mstore(add(start, 32), authorized_slot)
-
- // Revert if authorized[msg.sender] == false
- if iszero(sload(keccak256(start, 64))) {
- // Revert with `Error("SENDER_NOT_AUTHORIZED")`
- mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
- mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
- mstore(64, 0x0000001553454e4445525f4e4f545f415554484f52495a454400000000000000)
- mstore(96, 0)
- revert(0, 100)
- }
-
- // `transferFrom`.
- // The function is marked `external`, so no abi decodeding is done for
- // us. Instead, we expect the `calldata` memory to contain the
- // following:
- //
- // | Area | Offset | Length | Contents |
- // |----------|--------|---------|-------------------------------------|
- // | Header | 0 | 4 | function selector |
- // | Params | | 4 * 32 | function parameters: |
- // | | 4 | | 1. offset to assetData (*) |
- // | | 36 | | 2. from |
- // | | 68 | | 3. to |
- // | | 100 | | 4. amount |
- // | Data | | | assetData: |
- // | | 132 | 32 | assetData Length |
- // | | 164 | ** | assetData Contents |
- //
- // (*): offset is computed from start of function parameters, so offset
- // by an additional 4 bytes in the calldata.
- //
- // (**): see table below to compute length of assetData Contents
- //
- // WARNING: The ABIv2 specification allows additional padding between
- // the Params and Data section. This will result in a larger
- // offset to assetData.
-
- // Asset data itself is encoded as follows:
- //
- // | Area | Offset | Length | Contents |
- // |----------|--------|---------|-------------------------------------|
- // | Header | 0 | 4 | function selector |
- // | Params | | 1 * 32 | function parameters: |
- // | | 4 | 12 + 20 | 1. token address |
-
- // We construct calldata for the `token.transferFrom` ABI.
- // The layout of this calldata is in the table below.
- //
- // | Area | Offset | Length | Contents |
- // |----------|--------|---------|-------------------------------------|
- // | Header | 0 | 4 | function selector |
- // | Params | | 3 * 32 | function parameters: |
- // | | 4 | | 1. from |
- // | | 36 | | 2. to |
- // | | 68 | | 3. amount |
-
- /////// Read token address from calldata ///////
- // * The token address is stored in `assetData`.
- //
- // * The "offset to assetData" is stored at offset 4 in the calldata (table 1).
- // [assetDataOffsetFromParams = calldataload(4)]
- //
- // * Notes that the "offset to assetData" is relative to the "Params" area of calldata;
- // add 4 bytes to account for the length of the "Header" area (table 1).
- // [assetDataOffsetFromHeader = assetDataOffsetFromParams + 4]
- //
- // * The "token address" is offset 32+4=36 bytes into "assetData" (tables 1 & 2).
- // [tokenOffset = assetDataOffsetFromHeader + 36 = calldataload(4) + 4 + 36]
- let token := calldataload(add(calldataload(4), 40))
-
- /////// Setup Header Area ///////
- // This area holds the 4-byte `transferFrom` selector.
- // Any trailing data in transferFromSelector will be
- // overwritten in the next `mstore` call.
- mstore(0, 0x23b872dd00000000000000000000000000000000000000000000000000000000)
-
- /////// Setup Params Area ///////
- // We copy the fields `from`, `to` and `amount` in bulk
- // from our own calldata to the new calldata.
- calldatacopy(4, 36, 96)
-
- /////// Call `token.transferFrom` using the calldata ///////
- let success := call(
- gas, // forward all gas
- token, // call address of token contract
- 0, // don't send any ETH
- 0, // pointer to start of input
- 100, // length of input
- 0, // write output over input
- 32 // output size should be 32 bytes
- )
-
- /////// 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
- // nonzero 32 bytes value.
- // So the transfer succeeded if the call succeeded and either
- // returned nothing, or returned a non-zero 32 byte value.
- success := and(success, or(
- iszero(returndatasize),
- and(
- eq(returndatasize, 32),
- gt(mload(0), 0)
- )
- ))
- if success {
- return(0, 0)
- }
-
- // Revert with `Error("TRANSFER_FAILED")`
- mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
- mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
- mstore(64, 0x0000000f5452414e534645525f4641494c454400000000000000000000000000)
- mstore(96, 0)
- revert(0, 100)
- }
-
- // Revert if undefined function is called
- revert(0, 0)
- }
- }
-
- /// @dev Gets the proxy id associated with the proxy address.
- /// @return Proxy id.
- function getProxyId()
- external
- pure
- returns (bytes4)
- {
- return PROXY_ID;
- }
-}
diff --git a/packages/contracts/contracts/protocol/AssetProxy/ERC721Proxy.sol b/packages/contracts/contracts/protocol/AssetProxy/ERC721Proxy.sol
deleted file mode 100644
index 65b664b8b..000000000
--- a/packages/contracts/contracts/protocol/AssetProxy/ERC721Proxy.sol
+++ /dev/null
@@ -1,171 +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 "./MixinAuthorizable.sol";
-
-
-contract ERC721Proxy is
- MixinAuthorizable
-{
- // Id of this proxy.
- bytes4 constant internal PROXY_ID = bytes4(keccak256("ERC721Token(address,uint256)"));
-
- // solhint-disable-next-line payable-fallback
- function ()
- external
- {
- assembly {
- // The first 4 bytes of calldata holds the function selector
- let selector := and(calldataload(0), 0xffffffff00000000000000000000000000000000000000000000000000000000)
-
- // `transferFrom` will be called with the following parameters:
- // assetData Encoded byte array.
- // from Address to transfer asset from.
- // to Address to transfer asset to.
- // amount Amount of asset to transfer.
- // bytes4(keccak256("transferFrom(bytes,address,address,uint256)")) = 0xa85e59e4
- if eq(selector, 0xa85e59e400000000000000000000000000000000000000000000000000000000) {
-
- // To lookup a value in a mapping, we load from the storage location keccak256(k, p),
- // where k is the key left padded to 32 bytes and p is the storage slot
- let start := mload(64)
- mstore(start, and(caller, 0xffffffffffffffffffffffffffffffffffffffff))
- mstore(add(start, 32), authorized_slot)
-
- // Revert if authorized[msg.sender] == false
- if iszero(sload(keccak256(start, 64))) {
- // Revert with `Error("SENDER_NOT_AUTHORIZED")`
- mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
- mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
- mstore(64, 0x0000001553454e4445525f4e4f545f415554484f52495a454400000000000000)
- mstore(96, 0)
- revert(0, 100)
- }
-
- // `transferFrom`.
- // The function is marked `external`, so no abi decodeding is done for
- // us. Instead, we expect the `calldata` memory to contain the
- // following:
- //
- // | Area | Offset | Length | Contents |
- // |----------|--------|---------|-------------------------------------|
- // | Header | 0 | 4 | function selector |
- // | Params | | 4 * 32 | function parameters: |
- // | | 4 | | 1. offset to assetData (*) |
- // | | 36 | | 2. from |
- // | | 68 | | 3. to |
- // | | 100 | | 4. amount |
- // | Data | | | assetData: |
- // | | 132 | 32 | assetData Length |
- // | | 164 | ** | assetData Contents |
- //
- // (*): offset is computed from start of function parameters, so offset
- // by an additional 4 bytes in the calldata.
- //
- // (**): see table below to compute length of assetData Contents
- //
- // WARNING: The ABIv2 specification allows additional padding between
- // the Params and Data section. This will result in a larger
- // offset to assetData.
-
- // Asset data itself is encoded as follows:
- //
- // | Area | Offset | Length | Contents |
- // |----------|--------|---------|-------------------------------------|
- // | Header | 0 | 4 | function selector |
- // | Params | | 2 * 32 | function parameters: |
- // | | 4 | 12 + 20 | 1. token address |
- // | | 36 | | 2. tokenId |
-
- // We construct calldata for the `token.transferFrom` ABI.
- // The layout of this calldata is in the table below.
- //
- // | Area | Offset | Length | Contents |
- // |----------|--------|---------|-------------------------------------|
- // | Header | 0 | 4 | function selector |
- // | Params | | 3 * 32 | function parameters: |
- // | | 4 | | 1. from |
- // | | 36 | | 2. to |
- // | | 68 | | 3. tokenId |
-
- // There exists only 1 of each token.
- // require(amount == 1, "INVALID_AMOUNT")
- if sub(calldataload(100), 1) {
- // Revert with `Error("INVALID_AMOUNT")`
- mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
- mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
- mstore(64, 0x0000000e494e56414c49445f414d4f554e540000000000000000000000000000)
- mstore(96, 0)
- revert(0, 100)
- }
-
- /////// Setup Header Area ///////
- // This area holds the 4-byte `transferFrom` selector.
- // Any trailing data in transferFromSelector will be
- // overwritten in the next `mstore` call.
- mstore(0, 0x23b872dd00000000000000000000000000000000000000000000000000000000)
-
- /////// Setup Params Area ///////
- // We copy the fields `from` and `to` in bulk
- // from our own calldata to the new calldata.
- calldatacopy(4, 36, 64)
-
- // Copy `tokenId` field from our own calldata to the new calldata.
- let assetDataOffset := calldataload(4)
- calldatacopy(68, add(assetDataOffset, 72), 32)
-
- /////// Call `token.transferFrom` using the calldata ///////
- let token := calldataload(add(assetDataOffset, 40))
- let success := call(
- gas, // forward all gas
- token, // call address of token contract
- 0, // don't send any ETH
- 0, // pointer to start of input
- 100, // length of input
- 0, // write output to null
- 0 // output size is 0 bytes
- )
- if success {
- return(0, 0)
- }
-
- // Revert with `Error("TRANSFER_FAILED")`
- mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
- mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
- mstore(64, 0x0000000f5452414e534645525f4641494c454400000000000000000000000000)
- mstore(96, 0)
- revert(0, 100)
- }
-
- // Revert if undefined function is called
- revert(0, 0)
- }
- }
-
- /// @dev Gets the proxy id associated with the proxy address.
- /// @return Proxy id.
- function getProxyId()
- external
- pure
- returns (bytes4)
- {
- return PROXY_ID;
- }
-}
diff --git a/packages/contracts/contracts/protocol/AssetProxy/MixinAuthorizable.sol b/packages/contracts/contracts/protocol/AssetProxy/MixinAuthorizable.sol
deleted file mode 100644
index fe9bbf848..000000000
--- a/packages/contracts/contracts/protocol/AssetProxy/MixinAuthorizable.sol
+++ /dev/null
@@ -1,117 +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 "../../utils/Ownable/Ownable.sol";
-import "./mixins/MAuthorizable.sol";
-
-
-contract MixinAuthorizable is
- Ownable,
- MAuthorizable
-{
- /// @dev Only authorized addresses can invoke functions with this modifier.
- modifier onlyAuthorized {
- require(
- authorized[msg.sender],
- "SENDER_NOT_AUTHORIZED"
- );
- _;
- }
-
- mapping (address => bool) public authorized;
- address[] public authorities;
-
- /// @dev Authorizes an address.
- /// @param target Address to authorize.
- function addAuthorizedAddress(address target)
- external
- onlyOwner
- {
- require(
- !authorized[target],
- "TARGET_ALREADY_AUTHORIZED"
- );
-
- authorized[target] = true;
- authorities.push(target);
- emit AuthorizedAddressAdded(target, msg.sender);
- }
-
- /// @dev Removes authorizion of an address.
- /// @param target Address to remove authorization from.
- function removeAuthorizedAddress(address target)
- external
- onlyOwner
- {
- require(
- authorized[target],
- "TARGET_NOT_AUTHORIZED"
- );
-
- delete authorized[target];
- for (uint256 i = 0; i < authorities.length; i++) {
- if (authorities[i] == target) {
- authorities[i] = authorities[authorities.length - 1];
- authorities.length -= 1;
- break;
- }
- }
- emit AuthorizedAddressRemoved(target, msg.sender);
- }
-
- /// @dev Removes authorizion of an address.
- /// @param target Address to remove authorization from.
- /// @param index Index of target in authorities array.
- function removeAuthorizedAddressAtIndex(
- address target,
- uint256 index
- )
- external
- onlyOwner
- {
- require(
- authorized[target],
- "TARGET_NOT_AUTHORIZED"
- );
- require(
- index < authorities.length,
- "INDEX_OUT_OF_BOUNDS"
- );
- require(
- authorities[index] == target,
- "AUTHORIZED_ADDRESS_MISMATCH"
- );
-
- delete authorized[target];
- authorities[index] = authorities[authorities.length - 1];
- authorities.length -= 1;
- emit AuthorizedAddressRemoved(target, msg.sender);
- }
-
- /// @dev Gets all authorized addresses.
- /// @return Array of authorized addresses.
- function getAuthorizedAddresses()
- external
- view
- returns (address[] memory)
- {
- return authorities;
- }
-}
diff --git a/packages/contracts/contracts/protocol/AssetProxy/interfaces/IAssetData.sol b/packages/contracts/contracts/protocol/AssetProxy/interfaces/IAssetData.sol
deleted file mode 100644
index e2da68919..000000000
--- a/packages/contracts/contracts/protocol/AssetProxy/interfaces/IAssetData.sol
+++ /dev/null
@@ -1,44 +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;
-pragma experimental ABIEncoderV2;
-
-
-// @dev Interface of the asset proxy's assetData.
-// The asset proxies take an ABI encoded `bytes assetData` as argument.
-// This argument is ABI encoded as one of the methods of this interface.
-interface IAssetData {
-
- function ERC20Token(address tokenContract)
- external;
-
- function ERC721Token(
- address tokenContract,
- uint256 tokenId
- )
- external;
-
- function MultiAsset(
- uint256[] amounts,
- bytes[] nestedAssetData
- )
- external;
-
-}
diff --git a/packages/contracts/contracts/protocol/AssetProxy/interfaces/IAssetProxy.sol b/packages/contracts/contracts/protocol/AssetProxy/interfaces/IAssetProxy.sol
deleted file mode 100644
index b25d2d75a..000000000
--- a/packages/contracts/contracts/protocol/AssetProxy/interfaces/IAssetProxy.sol
+++ /dev/null
@@ -1,46 +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 "./IAuthorizable.sol";
-
-
-contract IAssetProxy is
- IAuthorizable
-{
- /// @dev Transfers assets. Either succeeds or throws.
- /// @param assetData Byte array encoded for the respective asset proxy.
- /// @param from Address to transfer asset from.
- /// @param to Address to transfer asset to.
- /// @param amount Amount of asset to transfer.
- function transferFrom(
- bytes assetData,
- address from,
- address to,
- uint256 amount
- )
- external;
-
- /// @dev Gets the proxy id associated with the proxy address.
- /// @return Proxy id.
- function getProxyId()
- external
- pure
- returns (bytes4);
-}
diff --git a/packages/contracts/contracts/protocol/AssetProxy/interfaces/IAuthorizable.sol b/packages/contracts/contracts/protocol/AssetProxy/interfaces/IAuthorizable.sol
deleted file mode 100644
index ba1d4aa77..000000000
--- a/packages/contracts/contracts/protocol/AssetProxy/interfaces/IAuthorizable.sol
+++ /dev/null
@@ -1,52 +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 "../../../utils/Ownable/IOwnable.sol";
-
-
-contract IAuthorizable is
- IOwnable
-{
- /// @dev Authorizes an address.
- /// @param target Address to authorize.
- function addAuthorizedAddress(address target)
- external;
-
- /// @dev Removes authorizion of an address.
- /// @param target Address to remove authorization from.
- function removeAuthorizedAddress(address target)
- external;
-
- /// @dev Removes authorizion of an address.
- /// @param target Address to remove authorization from.
- /// @param index Index of target in authorities array.
- function removeAuthorizedAddressAtIndex(
- address target,
- uint256 index
- )
- external;
-
- /// @dev Gets all authorized addresses.
- /// @return Array of authorized addresses.
- function getAuthorizedAddresses()
- external
- view
- returns (address[] memory);
-}
diff --git a/packages/contracts/contracts/protocol/AssetProxy/libs/LibAssetProxyErrors.sol b/packages/contracts/contracts/protocol/AssetProxy/libs/LibAssetProxyErrors.sol
deleted file mode 100644
index 1d9a70cc1..000000000
--- a/packages/contracts/contracts/protocol/AssetProxy/libs/LibAssetProxyErrors.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.
-
-*/
-
-// solhint-disable
-pragma solidity 0.4.24;
-
-
-/// @dev This contract documents the revert reasons used in the AssetProxy contracts.
-/// This contract is intended to serve as a reference, but is not actually used for efficiency reasons.
-contract LibAssetProxyErrors {
-
- /// Authorizable errors ///
- string constant SENDER_NOT_AUTHORIZED = "SENDER_NOT_AUTHORIZED"; // Sender not authorized to call this method.
- string constant TARGET_NOT_AUTHORIZED = "TARGET_NOT_AUTHORIZED"; // Target address not authorized to call this method.
- string constant TARGET_ALREADY_AUTHORIZED = "TARGET_ALREADY_AUTHORIZED"; // Target address must not already be authorized.
- string constant INDEX_OUT_OF_BOUNDS = "INDEX_OUT_OF_BOUNDS"; // Specified array index is out of bounds.
- string constant AUTHORIZED_ADDRESS_MISMATCH = "AUTHORIZED_ADDRESS_MISMATCH"; // Address at index does not match given target address.
-
- /// Transfer errors ///
- string constant INVALID_AMOUNT = "INVALID_AMOUNT"; // Transfer amount must equal 1.
- string constant TRANSFER_FAILED = "TRANSFER_FAILED"; // Transfer failed.
- string constant LENGTH_GREATER_THAN_131_REQUIRED = "LENGTH_GREATER_THAN_131_REQUIRED"; // Byte array must have a length greater than 0.
-}
diff --git a/packages/contracts/contracts/protocol/AssetProxy/mixins/MAuthorizable.sol b/packages/contracts/contracts/protocol/AssetProxy/mixins/MAuthorizable.sol
deleted file mode 100644
index d63fb7f6d..000000000
--- a/packages/contracts/contracts/protocol/AssetProxy/mixins/MAuthorizable.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;
-
-import "../interfaces/IAuthorizable.sol";
-
-
-contract MAuthorizable is
- IAuthorizable
-{
- // Event logged when a new address is authorized.
- event AuthorizedAddressAdded(
- address indexed target,
- address indexed caller
- );
-
- // Event logged when a currently authorized address is unauthorized.
- event AuthorizedAddressRemoved(
- address indexed target,
- address indexed caller
- );
-
- /// @dev Only authorized addresses can invoke functions with this modifier.
- modifier onlyAuthorized { revert(); _; }
-}
diff --git a/packages/contracts/contracts/protocol/AssetProxyOwner/AssetProxyOwner.sol b/packages/contracts/contracts/protocol/AssetProxyOwner/AssetProxyOwner.sol
deleted file mode 100644
index edb788fab..000000000
--- a/packages/contracts/contracts/protocol/AssetProxyOwner/AssetProxyOwner.sol
+++ /dev/null
@@ -1,108 +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 "../../multisig/MultiSigWalletWithTimeLock.sol";
-import "../../utils/LibBytes/LibBytes.sol";
-
-
-contract AssetProxyOwner is
- MultiSigWalletWithTimeLock
-{
- using LibBytes for bytes;
-
- event AssetProxyRegistration(address assetProxyContract, bool isRegistered);
-
- // Mapping of AssetProxy contract address =>
- // if this contract is allowed to call the AssetProxy's `removeAuthorizedAddressAtIndex` method without a time lock.
- mapping (address => bool) public isAssetProxyRegistered;
-
- bytes4 constant internal REMOVE_AUTHORIZED_ADDRESS_AT_INDEX_SELECTOR = bytes4(keccak256("removeAuthorizedAddressAtIndex(address,uint256)"));
-
- /// @dev Function will revert if the transaction does not call `removeAuthorizedAddressAtIndex`
- /// on an approved AssetProxy contract.
- modifier validRemoveAuthorizedAddressAtIndexTx(uint256 transactionId) {
- Transaction storage txn = transactions[transactionId];
- require(
- isAssetProxyRegistered[txn.destination],
- "UNREGISTERED_ASSET_PROXY"
- );
- require(
- txn.data.readBytes4(0) == REMOVE_AUTHORIZED_ADDRESS_AT_INDEX_SELECTOR,
- "INVALID_FUNCTION_SELECTOR"
- );
- _;
- }
-
- /// @dev Contract constructor sets initial owners, required number of confirmations,
- /// time lock, and list of AssetProxy addresses.
- /// @param _owners List of initial owners.
- /// @param _assetProxyContracts Array of AssetProxy contract addresses.
- /// @param _required Number of required confirmations.
- /// @param _secondsTimeLocked Duration needed after a transaction is confirmed and before it becomes executable, in seconds.
- constructor (
- address[] memory _owners,
- address[] memory _assetProxyContracts,
- uint256 _required,
- uint256 _secondsTimeLocked
- )
- public
- MultiSigWalletWithTimeLock(_owners, _required, _secondsTimeLocked)
- {
- for (uint256 i = 0; i < _assetProxyContracts.length; i++) {
- address assetProxy = _assetProxyContracts[i];
- require(
- assetProxy != address(0),
- "INVALID_ASSET_PROXY"
- );
- isAssetProxyRegistered[assetProxy] = true;
- }
- }
-
- /// @dev Registers or deregisters an AssetProxy to be able to execute
- /// `removeAuthorizedAddressAtIndex` without a timelock.
- /// @param assetProxyContract Address of AssetProxy contract.
- /// @param isRegistered Status of approval for AssetProxy contract.
- function registerAssetProxy(address assetProxyContract, bool isRegistered)
- public
- onlyWallet
- notNull(assetProxyContract)
- {
- isAssetProxyRegistered[assetProxyContract] = isRegistered;
- emit AssetProxyRegistration(assetProxyContract, isRegistered);
- }
-
- /// @dev Allows execution of `removeAuthorizedAddressAtIndex` without time lock.
- /// @param transactionId Transaction ID.
- function executeRemoveAuthorizedAddressAtIndex(uint256 transactionId)
- public
- notExecuted(transactionId)
- fullyConfirmed(transactionId)
- validRemoveAuthorizedAddressAtIndexTx(transactionId)
- {
- Transaction storage txn = transactions[transactionId];
- txn.executed = true;
- if (external_call(txn.destination, txn.value, txn.data.length, txn.data)) {
- emit Execution(transactionId);
- } else {
- emit ExecutionFailure(transactionId);
- txn.executed = false;
- }
- }
-}
diff --git a/packages/contracts/contracts/protocol/Exchange/Exchange.sol b/packages/contracts/contracts/protocol/Exchange/Exchange.sol
deleted file mode 100644
index ead36009f..000000000
--- a/packages/contracts/contracts/protocol/Exchange/Exchange.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;
-pragma experimental ABIEncoderV2;
-
-import "./libs/LibConstants.sol";
-import "./MixinExchangeCore.sol";
-import "./MixinSignatureValidator.sol";
-import "./MixinWrapperFunctions.sol";
-import "./MixinAssetProxyDispatcher.sol";
-import "./MixinTransactions.sol";
-import "./MixinMatchOrders.sol";
-
-
-// solhint-disable no-empty-blocks
-contract Exchange is
- MixinExchangeCore,
- MixinMatchOrders,
- MixinSignatureValidator,
- MixinTransactions,
- MixinAssetProxyDispatcher,
- MixinWrapperFunctions
-{
- string constant public VERSION = "2.0.1-alpha";
-
- // Mixins are instantiated in the order they are inherited
- constructor (bytes memory _zrxAssetData)
- public
- LibConstants(_zrxAssetData) // @TODO: Remove when we deploy.
- MixinExchangeCore()
- MixinMatchOrders()
- MixinSignatureValidator()
- MixinTransactions()
- MixinAssetProxyDispatcher()
- MixinWrapperFunctions()
- {}
-}
diff --git a/packages/contracts/contracts/protocol/Exchange/MixinAssetProxyDispatcher.sol b/packages/contracts/contracts/protocol/Exchange/MixinAssetProxyDispatcher.sol
deleted file mode 100644
index 87b09b6b3..000000000
--- a/packages/contracts/contracts/protocol/Exchange/MixinAssetProxyDispatcher.sol
+++ /dev/null
@@ -1,174 +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 "../../utils/Ownable/Ownable.sol";
-import "./mixins/MAssetProxyDispatcher.sol";
-import "../AssetProxy/interfaces/IAssetProxy.sol";
-
-
-contract MixinAssetProxyDispatcher is
- Ownable,
- MAssetProxyDispatcher
-{
- // Mapping from Asset Proxy Id's to their respective Asset Proxy
- mapping (bytes4 => IAssetProxy) public assetProxies;
-
- /// @dev Registers an asset proxy to its asset proxy id.
- /// Once an asset proxy is registered, it cannot be unregistered.
- /// @param assetProxy Address of new asset proxy to register.
- function registerAssetProxy(address assetProxy)
- external
- onlyOwner
- {
- IAssetProxy assetProxyContract = IAssetProxy(assetProxy);
-
- // Ensure that no asset proxy exists with current id.
- bytes4 assetProxyId = assetProxyContract.getProxyId();
- address currentAssetProxy = assetProxies[assetProxyId];
- require(
- currentAssetProxy == address(0),
- "ASSET_PROXY_ALREADY_EXISTS"
- );
-
- // Add asset proxy and log registration.
- assetProxies[assetProxyId] = assetProxyContract;
- emit AssetProxyRegistered(
- assetProxyId,
- assetProxy
- );
- }
-
- /// @dev Gets an asset proxy.
- /// @param assetProxyId Id of the asset proxy.
- /// @return The asset proxy registered to assetProxyId. Returns 0x0 if no proxy is registered.
- function getAssetProxy(bytes4 assetProxyId)
- external
- view
- returns (address)
- {
- return assetProxies[assetProxyId];
- }
-
- /// @dev Forwards arguments to assetProxy and calls `transferFrom`. Either succeeds or throws.
- /// @param assetData Byte array encoded for the asset.
- /// @param from Address to transfer token from.
- /// @param to Address to transfer token to.
- /// @param amount Amount of token to transfer.
- function dispatchTransferFrom(
- bytes memory assetData,
- address from,
- address to,
- uint256 amount
- )
- internal
- {
- // Do nothing if no amount should be transferred.
- if (amount > 0 && from != to) {
- // Ensure assetData length is valid
- require(
- assetData.length > 3,
- "LENGTH_GREATER_THAN_3_REQUIRED"
- );
-
- // Lookup assetProxy. We do not use `LibBytes.readBytes4` for gas efficiency reasons.
- bytes4 assetProxyId;
- assembly {
- assetProxyId := and(mload(
- add(assetData, 32)),
- 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000
- )
- }
- address assetProxy = assetProxies[assetProxyId];
-
- // Ensure that assetProxy exists
- require(
- assetProxy != address(0),
- "ASSET_PROXY_DOES_NOT_EXIST"
- );
-
- // We construct calldata for the `assetProxy.transferFrom` ABI.
- // The layout of this calldata is in the table below.
- //
- // | Area | Offset | Length | Contents |
- // | -------- |--------|---------|-------------------------------------------- |
- // | Header | 0 | 4 | function selector |
- // | Params | | 4 * 32 | function parameters: |
- // | | 4 | | 1. offset to assetData (*) |
- // | | 36 | | 2. from |
- // | | 68 | | 3. to |
- // | | 100 | | 4. amount |
- // | Data | | | assetData: |
- // | | 132 | 32 | assetData Length |
- // | | 164 | ** | assetData Contents |
-
- assembly {
- /////// Setup State ///////
- // `cdStart` is the start of the calldata for `assetProxy.transferFrom` (equal to free memory ptr).
- let cdStart := mload(64)
- // `dataAreaLength` is the total number of words needed to store `assetData`
- // As-per the ABI spec, this value is padded up to the nearest multiple of 32,
- // and includes 32-bytes for length.
- let dataAreaLength := and(add(mload(assetData), 63), 0xFFFFFFFFFFFE0)
- // `cdEnd` is the end of the calldata for `assetProxy.transferFrom`.
- let cdEnd := add(cdStart, add(132, dataAreaLength))
-
-
- /////// Setup Header Area ///////
- // This area holds the 4-byte `transferFromSelector`.
- // bytes4(keccak256("transferFrom(bytes,address,address,uint256)")) = 0xa85e59e4
- mstore(cdStart, 0xa85e59e400000000000000000000000000000000000000000000000000000000)
-
- /////// Setup Params Area ///////
- // Each parameter is padded to 32-bytes. The entire Params Area is 128 bytes.
- // Notes:
- // 1. The offset to `assetData` is the length of the Params Area (128 bytes).
- // 2. A 20-byte mask is applied to addresses to zero-out the unused bytes.
- mstore(add(cdStart, 4), 128)
- mstore(add(cdStart, 36), and(from, 0xffffffffffffffffffffffffffffffffffffffff))
- mstore(add(cdStart, 68), and(to, 0xffffffffffffffffffffffffffffffffffffffff))
- mstore(add(cdStart, 100), amount)
-
- /////// Setup Data Area ///////
- // This area holds `assetData`.
- let dataArea := add(cdStart, 132)
- // solhint-disable-next-line no-empty-blocks
- for {} lt(dataArea, cdEnd) {} {
- mstore(dataArea, mload(assetData))
- dataArea := add(dataArea, 32)
- assetData := add(assetData, 32)
- }
-
- /////// Call `assetProxy.transferFrom` using the constructed calldata ///////
- let success := call(
- gas, // forward all gas
- assetProxy, // call address of asset proxy
- 0, // don't send any ETH
- cdStart, // pointer to start of input
- sub(cdEnd, cdStart), // length of input
- cdStart, // write output over input
- 512 // reserve 512 bytes for output
- )
- if iszero(success) {
- revert(cdStart, returndatasize())
- }
- }
- }
- }
-}
diff --git a/packages/contracts/contracts/protocol/Exchange/MixinExchangeCore.sol b/packages/contracts/contracts/protocol/Exchange/MixinExchangeCore.sol
deleted file mode 100644
index 736dcd0b1..000000000
--- a/packages/contracts/contracts/protocol/Exchange/MixinExchangeCore.sol
+++ /dev/null
@@ -1,529 +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 "../../utils/ReentrancyGuard/ReentrancyGuard.sol";
-import "./libs/LibConstants.sol";
-import "./libs/LibFillResults.sol";
-import "./libs/LibOrder.sol";
-import "./libs/LibMath.sol";
-import "./mixins/MExchangeCore.sol";
-import "./mixins/MSignatureValidator.sol";
-import "./mixins/MTransactions.sol";
-import "./mixins/MAssetProxyDispatcher.sol";
-
-
-contract MixinExchangeCore is
- ReentrancyGuard,
- LibConstants,
- LibMath,
- LibOrder,
- LibFillResults,
- MAssetProxyDispatcher,
- MExchangeCore,
- MSignatureValidator,
- MTransactions
-{
- // Mapping of orderHash => amount of takerAsset already bought by maker
- mapping (bytes32 => uint256) public filled;
-
- // Mapping of orderHash => cancelled
- mapping (bytes32 => bool) public cancelled;
-
- // Mapping of makerAddress => senderAddress => lowest salt an order can have in order to be fillable
- // Orders with specified senderAddress and with a salt less than their epoch are considered cancelled
- mapping (address => mapping (address => uint256)) public orderEpoch;
-
- /// @dev Cancels all orders created by makerAddress with a salt less than or equal to the targetOrderEpoch
- /// and senderAddress equal to msg.sender (or null address if msg.sender == makerAddress).
- /// @param targetOrderEpoch Orders created with a salt less or equal to this value will be cancelled.
- function cancelOrdersUpTo(uint256 targetOrderEpoch)
- external
- nonReentrant
- {
- address makerAddress = getCurrentContextAddress();
- // If this function is called via `executeTransaction`, we only update the orderEpoch for the makerAddress/msg.sender combination.
- // This allows external filter contracts to add rules to how orders are cancelled via this function.
- address senderAddress = makerAddress == msg.sender ? address(0) : msg.sender;
-
- // orderEpoch is initialized to 0, so to cancelUpTo we need salt + 1
- uint256 newOrderEpoch = targetOrderEpoch + 1;
- uint256 oldOrderEpoch = orderEpoch[makerAddress][senderAddress];
-
- // Ensure orderEpoch is monotonically increasing
- require(
- newOrderEpoch > oldOrderEpoch,
- "INVALID_NEW_ORDER_EPOCH"
- );
-
- // Update orderEpoch
- orderEpoch[makerAddress][senderAddress] = newOrderEpoch;
- emit CancelUpTo(
- makerAddress,
- senderAddress,
- newOrderEpoch
- );
- }
-
- /// @dev Fills the input order.
- /// @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 fillOrder(
- Order memory order,
- uint256 takerAssetFillAmount,
- bytes memory signature
- )
- public
- nonReentrant
- returns (FillResults memory fillResults)
- {
- fillResults = fillOrderInternal(
- order,
- takerAssetFillAmount,
- signature
- );
- return fillResults;
- }
-
- /// @dev After calling, the order can not be filled anymore.
- /// Throws if order is invalid or sender does not have permission to cancel.
- /// @param order Order to cancel. Order must be OrderStatus.FILLABLE.
- function cancelOrder(Order memory order)
- public
- nonReentrant
- {
- cancelOrderInternal(order);
- }
-
- /// @dev Gets information about an order: status, hash, and amount filled.
- /// @param order Order to gather information on.
- /// @return OrderInfo Information about the order and its state.
- /// See LibOrder.OrderInfo for a complete description.
- function getOrderInfo(Order memory order)
- public
- view
- returns (OrderInfo memory orderInfo)
- {
- // Compute the order hash
- orderInfo.orderHash = getOrderHash(order);
-
- // Fetch filled amount
- orderInfo.orderTakerAssetFilledAmount = filled[orderInfo.orderHash];
-
- // If order.makerAssetAmount is zero, we also reject the order.
- // While the Exchange contract handles them correctly, they create
- // edge cases in the supporting infrastructure because they have
- // an 'infinite' price when computed by a simple division.
- if (order.makerAssetAmount == 0) {
- orderInfo.orderStatus = uint8(OrderStatus.INVALID_MAKER_ASSET_AMOUNT);
- return orderInfo;
- }
-
- // If order.takerAssetAmount is zero, then the order will always
- // be considered filled because 0 == takerAssetAmount == orderTakerAssetFilledAmount
- // Instead of distinguishing between unfilled and filled zero taker
- // amount orders, we choose not to support them.
- if (order.takerAssetAmount == 0) {
- orderInfo.orderStatus = uint8(OrderStatus.INVALID_TAKER_ASSET_AMOUNT);
- return orderInfo;
- }
-
- // Validate order availability
- if (orderInfo.orderTakerAssetFilledAmount >= order.takerAssetAmount) {
- orderInfo.orderStatus = uint8(OrderStatus.FULLY_FILLED);
- return orderInfo;
- }
-
- // Validate order expiration
- // solhint-disable-next-line not-rely-on-time
- if (block.timestamp >= order.expirationTimeSeconds) {
- orderInfo.orderStatus = uint8(OrderStatus.EXPIRED);
- return orderInfo;
- }
-
- // Check if order has been cancelled
- if (cancelled[orderInfo.orderHash]) {
- orderInfo.orderStatus = uint8(OrderStatus.CANCELLED);
- return orderInfo;
- }
- if (orderEpoch[order.makerAddress][order.senderAddress] > order.salt) {
- orderInfo.orderStatus = uint8(OrderStatus.CANCELLED);
- return orderInfo;
- }
-
- // All other statuses are ruled out: order is Fillable
- orderInfo.orderStatus = uint8(OrderStatus.FILLABLE);
- return orderInfo;
- }
-
- /// @dev Fills the input order.
- /// @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 fillOrderInternal(
- Order memory order,
- uint256 takerAssetFillAmount,
- bytes memory signature
- )
- internal
- returns (FillResults memory fillResults)
- {
- // Fetch order info
- OrderInfo memory orderInfo = getOrderInfo(order);
-
- // Fetch taker address
- address takerAddress = getCurrentContextAddress();
-
- // Assert that the order is fillable by taker
- assertFillableOrder(
- order,
- orderInfo,
- takerAddress,
- signature
- );
-
- // Get amount of takerAsset to fill
- uint256 remainingTakerAssetAmount = safeSub(order.takerAssetAmount, orderInfo.orderTakerAssetFilledAmount);
- uint256 takerAssetFilledAmount = min256(takerAssetFillAmount, remainingTakerAssetAmount);
-
- // Validate context
- assertValidFill(
- order,
- orderInfo,
- takerAssetFillAmount,
- takerAssetFilledAmount,
- fillResults.makerAssetFilledAmount
- );
-
- // Compute proportional fill amounts
- fillResults = calculateFillResults(order, takerAssetFilledAmount);
-
- // Update exchange internal state
- updateFilledState(
- order,
- takerAddress,
- orderInfo.orderHash,
- orderInfo.orderTakerAssetFilledAmount,
- fillResults
- );
-
- // Settle order
- settleOrder(
- order,
- takerAddress,
- fillResults
- );
-
- return fillResults;
- }
-
- /// @dev After calling, the order can not be filled anymore.
- /// Throws if order is invalid or sender does not have permission to cancel.
- /// @param order Order to cancel. Order must be OrderStatus.FILLABLE.
- function cancelOrderInternal(Order memory order)
- internal
- {
- // Fetch current order status
- OrderInfo memory orderInfo = getOrderInfo(order);
-
- // Validate context
- assertValidCancel(order, orderInfo);
-
- // Perform cancel
- updateCancelledState(order, orderInfo.orderHash);
- }
-
- /// @dev Updates state with results of a fill order.
- /// @param order that was filled.
- /// @param takerAddress Address of taker who filled the order.
- /// @param orderTakerAssetFilledAmount Amount of order already filled.
- function updateFilledState(
- Order memory order,
- address takerAddress,
- bytes32 orderHash,
- uint256 orderTakerAssetFilledAmount,
- FillResults memory fillResults
- )
- internal
- {
- // Update state
- filled[orderHash] = safeAdd(orderTakerAssetFilledAmount, fillResults.takerAssetFilledAmount);
-
- // Log order
- emit Fill(
- order.makerAddress,
- order.feeRecipientAddress,
- takerAddress,
- msg.sender,
- fillResults.makerAssetFilledAmount,
- fillResults.takerAssetFilledAmount,
- fillResults.makerFeePaid,
- fillResults.takerFeePaid,
- orderHash,
- order.makerAssetData,
- order.takerAssetData
- );
- }
-
- /// @dev Updates state with results of cancelling an order.
- /// State is only updated if the order is currently fillable.
- /// Otherwise, updating state would have no effect.
- /// @param order that was cancelled.
- /// @param orderHash Hash of order that was cancelled.
- function updateCancelledState(
- Order memory order,
- bytes32 orderHash
- )
- internal
- {
- // Perform cancel
- cancelled[orderHash] = true;
-
- // Log cancel
- emit Cancel(
- order.makerAddress,
- order.feeRecipientAddress,
- msg.sender,
- orderHash,
- order.makerAssetData,
- order.takerAssetData
- );
- }
-
- /// @dev Validates context for fillOrder. Succeeds or throws.
- /// @param order to be filled.
- /// @param orderInfo OrderStatus, orderHash, and amount already filled of order.
- /// @param takerAddress Address of order taker.
- /// @param signature Proof that the orders was created by its maker.
- function assertFillableOrder(
- Order memory order,
- OrderInfo memory orderInfo,
- address takerAddress,
- bytes memory signature
- )
- internal
- view
- {
- // An order can only be filled if its status is FILLABLE.
- require(
- orderInfo.orderStatus == uint8(OrderStatus.FILLABLE),
- "ORDER_UNFILLABLE"
- );
-
- // Validate sender is allowed to fill this order
- if (order.senderAddress != address(0)) {
- require(
- order.senderAddress == msg.sender,
- "INVALID_SENDER"
- );
- }
-
- // Validate taker is allowed to fill this order
- if (order.takerAddress != address(0)) {
- require(
- order.takerAddress == takerAddress,
- "INVALID_TAKER"
- );
- }
-
- // Validate Maker signature (check only if first time seen)
- if (orderInfo.orderTakerAssetFilledAmount == 0) {
- require(
- isValidSignature(
- orderInfo.orderHash,
- order.makerAddress,
- signature
- ),
- "INVALID_ORDER_SIGNATURE"
- );
- }
- }
-
- /// @dev Validates context for fillOrder. Succeeds or throws.
- /// @param order to be filled.
- /// @param orderInfo OrderStatus, orderHash, and amount already filled of order.
- /// @param takerAssetFillAmount Desired amount of order to fill by taker.
- /// @param takerAssetFilledAmount Amount of takerAsset that will be filled.
- /// @param makerAssetFilledAmount Amount of makerAsset that will be transfered.
- function assertValidFill(
- Order memory order,
- OrderInfo memory orderInfo,
- uint256 takerAssetFillAmount, // TODO: use FillResults
- uint256 takerAssetFilledAmount,
- uint256 makerAssetFilledAmount
- )
- internal
- view
- {
- // Revert if fill amount is invalid
- // TODO: reconsider necessity for v2.1
- require(
- takerAssetFillAmount != 0,
- "INVALID_TAKER_AMOUNT"
- );
-
- // Make sure taker does not pay more than desired amount
- // NOTE: This assertion should never fail, it is here
- // as an extra defence against potential bugs.
- require(
- takerAssetFilledAmount <= takerAssetFillAmount,
- "TAKER_OVERPAY"
- );
-
- // Make sure order is not overfilled
- // NOTE: This assertion should never fail, it is here
- // as an extra defence against potential bugs.
- require(
- safeAdd(orderInfo.orderTakerAssetFilledAmount, takerAssetFilledAmount) <= order.takerAssetAmount,
- "ORDER_OVERFILL"
- );
-
- // Make sure order is filled at acceptable price.
- // The order has an implied price from the makers perspective:
- // order price = order.makerAssetAmount / order.takerAssetAmount
- // i.e. the number of makerAsset maker is paying per takerAsset. The
- // maker is guaranteed to get this price or a better (lower) one. The
- // actual price maker is getting in this fill is:
- // fill price = makerAssetFilledAmount / takerAssetFilledAmount
- // We need `fill price <= order price` for the fill to be fair to maker.
- // This amounts to:
- // makerAssetFilledAmount order.makerAssetAmount
- // ------------------------ <= -----------------------
- // takerAssetFilledAmount order.takerAssetAmount
- // or, equivalently:
- // makerAssetFilledAmount * order.takerAssetAmount <=
- // order.makerAssetAmount * takerAssetFilledAmount
- // NOTE: This assertion should never fail, it is here
- // as an extra defence against potential bugs.
- require(
- safeMul(makerAssetFilledAmount, order.takerAssetAmount)
- <=
- safeMul(order.makerAssetAmount, takerAssetFilledAmount),
- "INVALID_FILL_PRICE"
- );
- }
-
- /// @dev Validates context for cancelOrder. Succeeds or throws.
- /// @param order to be cancelled.
- /// @param orderInfo OrderStatus, orderHash, and amount already filled of order.
- function assertValidCancel(
- Order memory order,
- OrderInfo memory orderInfo
- )
- internal
- view
- {
- // Ensure order is valid
- // An order can only be cancelled if its status is FILLABLE.
- require(
- orderInfo.orderStatus == uint8(OrderStatus.FILLABLE),
- "ORDER_UNFILLABLE"
- );
-
- // Validate sender is allowed to cancel this order
- if (order.senderAddress != address(0)) {
- require(
- order.senderAddress == msg.sender,
- "INVALID_SENDER"
- );
- }
-
- // Validate transaction signed by maker
- address makerAddress = getCurrentContextAddress();
- require(
- order.makerAddress == makerAddress,
- "INVALID_MAKER"
- );
- }
-
- /// @dev Calculates amounts filled and fees paid by maker and taker.
- /// @param order to be filled.
- /// @param takerAssetFilledAmount Amount of takerAsset that will be filled.
- /// @return fillResults Amounts filled and fees paid by maker and taker.
- function calculateFillResults(
- Order memory order,
- uint256 takerAssetFilledAmount
- )
- internal
- pure
- returns (FillResults memory fillResults)
- {
- // Compute proportional transfer amounts
- fillResults.takerAssetFilledAmount = takerAssetFilledAmount;
- fillResults.makerAssetFilledAmount = safeGetPartialAmountFloor(
- takerAssetFilledAmount,
- order.takerAssetAmount,
- order.makerAssetAmount
- );
- fillResults.makerFeePaid = safeGetPartialAmountFloor(
- fillResults.makerAssetFilledAmount,
- order.makerAssetAmount,
- order.makerFee
- );
- fillResults.takerFeePaid = safeGetPartialAmountFloor(
- takerAssetFilledAmount,
- order.takerAssetAmount,
- order.takerFee
- );
-
- return fillResults;
- }
-
- /// @dev Settles an order by transferring assets between counterparties.
- /// @param order Order struct containing order specifications.
- /// @param takerAddress Address selling takerAsset and buying makerAsset.
- /// @param fillResults Amounts to be filled and fees paid by maker and taker.
- function settleOrder(
- LibOrder.Order memory order,
- address takerAddress,
- LibFillResults.FillResults memory fillResults
- )
- private
- {
- bytes memory zrxAssetData = ZRX_ASSET_DATA;
- dispatchTransferFrom(
- order.makerAssetData,
- order.makerAddress,
- takerAddress,
- fillResults.makerAssetFilledAmount
- );
- dispatchTransferFrom(
- order.takerAssetData,
- takerAddress,
- order.makerAddress,
- fillResults.takerAssetFilledAmount
- );
- dispatchTransferFrom(
- zrxAssetData,
- order.makerAddress,
- order.feeRecipientAddress,
- fillResults.makerFeePaid
- );
- dispatchTransferFrom(
- zrxAssetData,
- takerAddress,
- order.feeRecipientAddress,
- fillResults.takerFeePaid
- );
- }
-}
diff --git a/packages/contracts/contracts/protocol/Exchange/MixinMatchOrders.sol b/packages/contracts/contracts/protocol/Exchange/MixinMatchOrders.sol
deleted file mode 100644
index b4f6bdb26..000000000
--- a/packages/contracts/contracts/protocol/Exchange/MixinMatchOrders.sol
+++ /dev/null
@@ -1,335 +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 "../../utils/ReentrancyGuard/ReentrancyGuard.sol";
-import "./libs/LibConstants.sol";
-import "./libs/LibMath.sol";
-import "./libs/LibOrder.sol";
-import "./libs/LibFillResults.sol";
-import "./mixins/MExchangeCore.sol";
-import "./mixins/MMatchOrders.sol";
-import "./mixins/MTransactions.sol";
-import "./mixins/MAssetProxyDispatcher.sol";
-
-
-contract MixinMatchOrders is
- ReentrancyGuard,
- LibConstants,
- LibMath,
- MAssetProxyDispatcher,
- MExchangeCore,
- MMatchOrders,
- MTransactions
-{
- /// @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 goes to the taker (who matched the two orders).
- /// @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.
- /// @return matchedFillResults Amounts filled and fees paid by maker and taker of matched orders.
- function matchOrders(
- LibOrder.Order memory leftOrder,
- LibOrder.Order memory rightOrder,
- bytes memory leftSignature,
- bytes memory rightSignature
- )
- public
- nonReentrant
- returns (LibFillResults.MatchedFillResults memory matchedFillResults)
- {
- // We assume that rightOrder.takerAssetData == leftOrder.makerAssetData and rightOrder.makerAssetData == leftOrder.takerAssetData.
- // If this assumption isn't true, the match will fail at signature validation.
- rightOrder.makerAssetData = leftOrder.takerAssetData;
- rightOrder.takerAssetData = leftOrder.makerAssetData;
-
- // Get left & right order info
- LibOrder.OrderInfo memory leftOrderInfo = getOrderInfo(leftOrder);
- LibOrder.OrderInfo memory rightOrderInfo = getOrderInfo(rightOrder);
-
- // Fetch taker address
- address takerAddress = getCurrentContextAddress();
-
- // Either our context is valid or we revert
- assertFillableOrder(
- leftOrder,
- leftOrderInfo,
- takerAddress,
- leftSignature
- );
- assertFillableOrder(
- rightOrder,
- rightOrderInfo,
- takerAddress,
- rightSignature
- );
- assertValidMatch(leftOrder, rightOrder);
-
- // Compute proportional fill amounts
- matchedFillResults = calculateMatchedFillResults(
- leftOrder,
- rightOrder,
- leftOrderInfo.orderTakerAssetFilledAmount,
- rightOrderInfo.orderTakerAssetFilledAmount
- );
-
- // Validate fill contexts
- assertValidFill(
- leftOrder,
- leftOrderInfo,
- matchedFillResults.left.takerAssetFilledAmount,
- matchedFillResults.left.takerAssetFilledAmount,
- matchedFillResults.left.makerAssetFilledAmount
- );
- assertValidFill(
- rightOrder,
- rightOrderInfo,
- matchedFillResults.right.takerAssetFilledAmount,
- matchedFillResults.right.takerAssetFilledAmount,
- matchedFillResults.right.makerAssetFilledAmount
- );
-
- // Update exchange state
- updateFilledState(
- leftOrder,
- takerAddress,
- leftOrderInfo.orderHash,
- leftOrderInfo.orderTakerAssetFilledAmount,
- matchedFillResults.left
- );
- updateFilledState(
- rightOrder,
- takerAddress,
- rightOrderInfo.orderHash,
- rightOrderInfo.orderTakerAssetFilledAmount,
- matchedFillResults.right
- );
-
- // Settle matched orders. Succeeds or throws.
- settleMatchedOrders(
- leftOrder,
- rightOrder,
- takerAddress,
- matchedFillResults
- );
-
- return matchedFillResults;
- }
-
- /// @dev Validates context for matchOrders. Succeeds or throws.
- /// @param leftOrder First order to match.
- /// @param rightOrder Second order to match.
- function assertValidMatch(
- LibOrder.Order memory leftOrder,
- LibOrder.Order memory rightOrder
- )
- internal
- pure
- {
- // Make sure there is a profitable spread.
- // There is a profitable spread iff the cost per unit bought (OrderA.MakerAmount/OrderA.TakerAmount) for each order is greater
- // than the profit per unit sold of the matched order (OrderB.TakerAmount/OrderB.MakerAmount).
- // This is satisfied by the equations below:
- // <leftOrder.makerAssetAmount> / <leftOrder.takerAssetAmount> >= <rightOrder.takerAssetAmount> / <rightOrder.makerAssetAmount>
- // AND
- // <rightOrder.makerAssetAmount> / <rightOrder.takerAssetAmount> >= <leftOrder.takerAssetAmount> / <leftOrder.makerAssetAmount>
- // These equations can be combined to get the following:
- require(
- safeMul(leftOrder.makerAssetAmount, rightOrder.makerAssetAmount) >=
- safeMul(leftOrder.takerAssetAmount, rightOrder.takerAssetAmount),
- "NEGATIVE_SPREAD_REQUIRED"
- );
- }
-
- /// @dev Calculates fill amounts for the matched orders.
- /// 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 leftOrder order goes to the taker (who matched the two orders).
- /// @param leftOrder First order to match.
- /// @param rightOrder Second order to match.
- /// @param leftOrderTakerAssetFilledAmount Amount of left order already filled.
- /// @param rightOrderTakerAssetFilledAmount Amount of right order already filled.
- /// @param matchedFillResults Amounts to fill and fees to pay by maker and taker of matched orders.
- function calculateMatchedFillResults(
- LibOrder.Order memory leftOrder,
- LibOrder.Order memory rightOrder,
- uint256 leftOrderTakerAssetFilledAmount,
- uint256 rightOrderTakerAssetFilledAmount
- )
- internal
- pure
- returns (LibFillResults.MatchedFillResults memory matchedFillResults)
- {
- // Derive maker asset amounts for left & right orders, given store taker assert amounts
- uint256 leftTakerAssetAmountRemaining = safeSub(leftOrder.takerAssetAmount, leftOrderTakerAssetFilledAmount);
- uint256 leftMakerAssetAmountRemaining = safeGetPartialAmountFloor(
- leftOrder.makerAssetAmount,
- leftOrder.takerAssetAmount,
- leftTakerAssetAmountRemaining
- );
- uint256 rightTakerAssetAmountRemaining = safeSub(rightOrder.takerAssetAmount, rightOrderTakerAssetFilledAmount);
- uint256 rightMakerAssetAmountRemaining = safeGetPartialAmountFloor(
- rightOrder.makerAssetAmount,
- rightOrder.takerAssetAmount,
- rightTakerAssetAmountRemaining
- );
-
- // Calculate fill results for maker and taker assets: at least one order will be fully filled.
- // The maximum amount the left maker can buy is `leftTakerAssetAmountRemaining`
- // The maximum amount the right maker can sell is `rightMakerAssetAmountRemaining`
- // We have two distinct cases for calculating the fill results:
- // Case 1.
- // If the left maker can buy more than the right maker can sell, then only the right order is fully filled.
- // If the left maker can buy exactly what the right maker can sell, then both orders are fully filled.
- // Case 2.
- // If the left maker cannot buy more than the right maker can sell, then only the left order is fully filled.
- if (leftTakerAssetAmountRemaining >= rightMakerAssetAmountRemaining) {
- // Case 1: Right order is fully filled
- matchedFillResults.right.makerAssetFilledAmount = rightMakerAssetAmountRemaining;
- matchedFillResults.right.takerAssetFilledAmount = rightTakerAssetAmountRemaining;
- matchedFillResults.left.takerAssetFilledAmount = matchedFillResults.right.makerAssetFilledAmount;
- // Round down to ensure the maker's exchange rate does not exceed the price specified by the order.
- // We favor the maker when the exchange rate must be rounded.
- matchedFillResults.left.makerAssetFilledAmount = safeGetPartialAmountFloor(
- leftOrder.makerAssetAmount,
- leftOrder.takerAssetAmount,
- matchedFillResults.left.takerAssetFilledAmount
- );
- } else {
- // Case 2: Left order is fully filled
- matchedFillResults.left.makerAssetFilledAmount = leftMakerAssetAmountRemaining;
- matchedFillResults.left.takerAssetFilledAmount = leftTakerAssetAmountRemaining;
- matchedFillResults.right.makerAssetFilledAmount = matchedFillResults.left.takerAssetFilledAmount;
- // Round up to ensure the maker's exchange rate does not exceed the price specified by the order.
- // We favor the maker when the exchange rate must be rounded.
- matchedFillResults.right.takerAssetFilledAmount = safeGetPartialAmountCeil(
- rightOrder.takerAssetAmount,
- rightOrder.makerAssetAmount,
- matchedFillResults.right.makerAssetFilledAmount
- );
- }
-
- // Calculate amount given to taker
- matchedFillResults.leftMakerAssetSpreadAmount = safeSub(
- matchedFillResults.left.makerAssetFilledAmount,
- matchedFillResults.right.takerAssetFilledAmount
- );
-
- // Compute fees for left order
- matchedFillResults.left.makerFeePaid = safeGetPartialAmountFloor(
- matchedFillResults.left.makerAssetFilledAmount,
- leftOrder.makerAssetAmount,
- leftOrder.makerFee
- );
- matchedFillResults.left.takerFeePaid = safeGetPartialAmountFloor(
- matchedFillResults.left.takerAssetFilledAmount,
- leftOrder.takerAssetAmount,
- leftOrder.takerFee
- );
-
- // Compute fees for right order
- matchedFillResults.right.makerFeePaid = safeGetPartialAmountFloor(
- matchedFillResults.right.makerAssetFilledAmount,
- rightOrder.makerAssetAmount,
- rightOrder.makerFee
- );
- matchedFillResults.right.takerFeePaid = safeGetPartialAmountFloor(
- matchedFillResults.right.takerAssetFilledAmount,
- rightOrder.takerAssetAmount,
- rightOrder.takerFee
- );
-
- // Return fill results
- return matchedFillResults;
- }
-
- /// @dev Settles matched order by transferring appropriate funds between order makers, taker, and fee recipient.
- /// @param leftOrder First matched order.
- /// @param rightOrder Second matched order.
- /// @param takerAddress Address that matched the orders. The taker receives the spread between orders as profit.
- /// @param matchedFillResults Struct holding amounts to transfer between makers, taker, and fee recipients.
- function settleMatchedOrders(
- LibOrder.Order memory leftOrder,
- LibOrder.Order memory rightOrder,
- address takerAddress,
- LibFillResults.MatchedFillResults memory matchedFillResults
- )
- private
- {
- bytes memory zrxAssetData = ZRX_ASSET_DATA;
- // Order makers and taker
- dispatchTransferFrom(
- leftOrder.makerAssetData,
- leftOrder.makerAddress,
- rightOrder.makerAddress,
- matchedFillResults.right.takerAssetFilledAmount
- );
- dispatchTransferFrom(
- rightOrder.makerAssetData,
- rightOrder.makerAddress,
- leftOrder.makerAddress,
- matchedFillResults.left.takerAssetFilledAmount
- );
- dispatchTransferFrom(
- leftOrder.makerAssetData,
- leftOrder.makerAddress,
- takerAddress,
- matchedFillResults.leftMakerAssetSpreadAmount
- );
-
- // Maker fees
- dispatchTransferFrom(
- zrxAssetData,
- leftOrder.makerAddress,
- leftOrder.feeRecipientAddress,
- matchedFillResults.left.makerFeePaid
- );
- dispatchTransferFrom(
- zrxAssetData,
- rightOrder.makerAddress,
- rightOrder.feeRecipientAddress,
- matchedFillResults.right.makerFeePaid
- );
-
- // Taker fees
- if (leftOrder.feeRecipientAddress == rightOrder.feeRecipientAddress) {
- dispatchTransferFrom(
- zrxAssetData,
- takerAddress,
- leftOrder.feeRecipientAddress,
- safeAdd(
- matchedFillResults.left.takerFeePaid,
- matchedFillResults.right.takerFeePaid
- )
- );
- } else {
- dispatchTransferFrom(
- zrxAssetData,
- takerAddress,
- leftOrder.feeRecipientAddress,
- matchedFillResults.left.takerFeePaid
- );
- dispatchTransferFrom(
- zrxAssetData,
- takerAddress,
- rightOrder.feeRecipientAddress,
- matchedFillResults.right.takerFeePaid
- );
- }
- }
-}
diff --git a/packages/contracts/contracts/protocol/Exchange/MixinSignatureValidator.sol b/packages/contracts/contracts/protocol/Exchange/MixinSignatureValidator.sol
deleted file mode 100644
index 176e28351..000000000
--- a/packages/contracts/contracts/protocol/Exchange/MixinSignatureValidator.sol
+++ /dev/null
@@ -1,324 +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 "../../utils/LibBytes/LibBytes.sol";
-import "../../utils/ReentrancyGuard/ReentrancyGuard.sol";
-import "./mixins/MSignatureValidator.sol";
-import "./mixins/MTransactions.sol";
-import "./interfaces/IWallet.sol";
-import "./interfaces/IValidator.sol";
-
-
-contract MixinSignatureValidator is
- ReentrancyGuard,
- MSignatureValidator,
- MTransactions
-{
- using LibBytes for bytes;
-
- // Mapping of hash => signer => signed
- mapping (bytes32 => mapping (address => bool)) public preSigned;
-
- // Mapping of signer => validator => approved
- mapping (address => mapping (address => bool)) public allowedValidators;
-
- /// @dev Approves a hash on-chain using any valid signature type.
- /// After presigning a hash, the preSign signature type will become valid for that hash and signer.
- /// @param signerAddress Address that should have signed the given hash.
- /// @param signature Proof that the hash has been signed by signer.
- function preSign(
- bytes32 hash,
- address signerAddress,
- bytes signature
- )
- external
- {
- if (signerAddress != msg.sender) {
- require(
- isValidSignature(
- hash,
- signerAddress,
- signature
- ),
- "INVALID_SIGNATURE"
- );
- }
- preSigned[hash][signerAddress] = true;
- }
-
- /// @dev Approves/unnapproves a Validator contract to verify signatures on signer's behalf.
- /// @param validatorAddress Address of Validator contract.
- /// @param approval Approval or disapproval of Validator contract.
- function setSignatureValidatorApproval(
- address validatorAddress,
- bool approval
- )
- external
- nonReentrant
- {
- address signerAddress = getCurrentContextAddress();
- allowedValidators[signerAddress][validatorAddress] = approval;
- emit SignatureValidatorApproval(
- signerAddress,
- validatorAddress,
- approval
- );
- }
-
- /// @dev Verifies that a hash has been signed by the given signer.
- /// @param hash Any 32 byte hash.
- /// @param signerAddress Address that should have signed the given hash.
- /// @param signature Proof that the hash has been signed by signer.
- /// @return True if the address recovered from the provided signature matches the input signer address.
- function isValidSignature(
- bytes32 hash,
- address signerAddress,
- bytes memory signature
- )
- public
- view
- returns (bool isValid)
- {
- require(
- signature.length > 0,
- "LENGTH_GREATER_THAN_0_REQUIRED"
- );
-
- // Pop last byte off of signature byte array.
- uint8 signatureTypeRaw = uint8(signature.popLastByte());
-
- // Ensure signature is supported
- require(
- signatureTypeRaw < uint8(SignatureType.NSignatureTypes),
- "SIGNATURE_UNSUPPORTED"
- );
-
- SignatureType signatureType = SignatureType(signatureTypeRaw);
-
- // Variables are not scoped in Solidity.
- uint8 v;
- bytes32 r;
- bytes32 s;
- address recovered;
-
- // Always illegal signature.
- // This is always an implicit option since a signer can create a
- // signature array with invalid type or length. We may as well make
- // it an explicit option. This aids testing and analysis. It is
- // also the initialization value for the enum type.
- if (signatureType == SignatureType.Illegal) {
- revert("SIGNATURE_ILLEGAL");
-
- // Always invalid signature.
- // Like Illegal, this is always implicitly available and therefore
- // offered explicitly. It can be implicitly created by providing
- // a correctly formatted but incorrect signature.
- } else if (signatureType == SignatureType.Invalid) {
- require(
- signature.length == 0,
- "LENGTH_0_REQUIRED"
- );
- isValid = false;
- return isValid;
-
- // Signature using EIP712
- } else if (signatureType == SignatureType.EIP712) {
- require(
- signature.length == 65,
- "LENGTH_65_REQUIRED"
- );
- v = uint8(signature[0]);
- r = signature.readBytes32(1);
- s = signature.readBytes32(33);
- recovered = ecrecover(
- hash,
- v,
- r,
- s
- );
- isValid = signerAddress == recovered;
- return isValid;
-
- // Signed using web3.eth_sign
- } else if (signatureType == SignatureType.EthSign) {
- require(
- signature.length == 65,
- "LENGTH_65_REQUIRED"
- );
- v = uint8(signature[0]);
- r = signature.readBytes32(1);
- s = signature.readBytes32(33);
- recovered = ecrecover(
- keccak256(abi.encodePacked(
- "\x19Ethereum Signed Message:\n32",
- hash
- )),
- v,
- r,
- s
- );
- isValid = signerAddress == recovered;
- return isValid;
-
- // Signature verified by wallet contract.
- // If used with an order, the maker of the order is the wallet contract.
- } else if (signatureType == SignatureType.Wallet) {
- isValid = isValidWalletSignature(
- hash,
- signerAddress,
- signature
- );
- return isValid;
-
- // Signature verified by validator contract.
- // If used with an order, the maker of the order can still be an EOA.
- // A signature using this type should be encoded as:
- // | Offset | Length | Contents |
- // | 0x00 | x | Signature to validate |
- // | 0x00 + x | 20 | Address of validator contract |
- // | 0x14 + x | 1 | Signature type is always "\x06" |
- } else if (signatureType == SignatureType.Validator) {
- // Pop last 20 bytes off of signature byte array.
- address validatorAddress = signature.popLast20Bytes();
-
- // Ensure signer has approved validator.
- if (!allowedValidators[signerAddress][validatorAddress]) {
- return false;
- }
- isValid = isValidValidatorSignature(
- validatorAddress,
- hash,
- signerAddress,
- signature
- );
- return isValid;
-
- // Signer signed hash previously using the preSign function.
- } else if (signatureType == SignatureType.PreSigned) {
- isValid = preSigned[hash][signerAddress];
- return isValid;
- }
-
- // Anything else is illegal (We do not return false because
- // the signature may actually be valid, just not in a format
- // that we currently support. In this case returning false
- // may lead the caller to incorrectly believe that the
- // signature was invalid.)
- revert("SIGNATURE_UNSUPPORTED");
- }
-
- /// @dev Verifies signature using logic defined by Wallet contract.
- /// @param hash Any 32 byte hash.
- /// @param walletAddress Address that should have signed the given hash
- /// and defines its own signature verification method.
- /// @param signature Proof that the hash has been signed by signer.
- /// @return True if signature is valid for given wallet..
- function isValidWalletSignature(
- bytes32 hash,
- address walletAddress,
- bytes signature
- )
- internal
- view
- returns (bool isValid)
- {
- bytes memory calldata = abi.encodeWithSelector(
- IWallet(walletAddress).isValidSignature.selector,
- hash,
- signature
- );
- assembly {
- let cdStart := add(calldata, 32)
- let success := staticcall(
- gas, // forward all gas
- walletAddress, // address of Wallet contract
- cdStart, // pointer to start of input
- mload(calldata), // length of input
- cdStart, // write output over input
- 32 // output size is 32 bytes
- )
-
- switch success
- case 0 {
- // Revert with `Error("WALLET_ERROR")`
- mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
- mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
- mstore(64, 0x0000000c57414c4c45545f4552524f5200000000000000000000000000000000)
- mstore(96, 0)
- revert(0, 100)
- }
- case 1 {
- // Signature is valid if call did not revert and returned true
- isValid := mload(cdStart)
- }
- }
- return isValid;
- }
-
- /// @dev Verifies signature using logic defined by Validator contract.
- /// @param validatorAddress Address of validator contract.
- /// @param hash Any 32 byte hash.
- /// @param signerAddress Address that should have signed the given hash.
- /// @param signature Proof that the hash has been signed by signer.
- /// @return True if the address recovered from the provided signature matches the input signer address.
- function isValidValidatorSignature(
- address validatorAddress,
- bytes32 hash,
- address signerAddress,
- bytes signature
- )
- internal
- view
- returns (bool isValid)
- {
- bytes memory calldata = abi.encodeWithSelector(
- IValidator(signerAddress).isValidSignature.selector,
- hash,
- signerAddress,
- signature
- );
- assembly {
- let cdStart := add(calldata, 32)
- let success := staticcall(
- gas, // forward all gas
- validatorAddress, // address of Validator contract
- cdStart, // pointer to start of input
- mload(calldata), // length of input
- cdStart, // write output over input
- 32 // output size is 32 bytes
- )
-
- switch success
- case 0 {
- // Revert with `Error("VALIDATOR_ERROR")`
- mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
- mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
- mstore(64, 0x0000000f56414c494441544f525f4552524f5200000000000000000000000000)
- mstore(96, 0)
- revert(0, 100)
- }
- case 1 {
- // Signature is valid if call did not revert and returned true
- isValid := mload(cdStart)
- }
- }
- return isValid;
- }
-}
diff --git a/packages/contracts/contracts/protocol/Exchange/MixinTransactions.sol b/packages/contracts/contracts/protocol/Exchange/MixinTransactions.sol
deleted file mode 100644
index 3a76ca202..000000000
--- a/packages/contracts/contracts/protocol/Exchange/MixinTransactions.sol
+++ /dev/null
@@ -1,152 +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 "./libs/LibExchangeErrors.sol";
-import "./mixins/MSignatureValidator.sol";
-import "./mixins/MTransactions.sol";
-import "./libs/LibEIP712.sol";
-
-
-contract MixinTransactions is
- LibEIP712,
- MSignatureValidator,
- MTransactions
-{
- // Mapping of transaction hash => executed
- // This prevents transactions from being executed more than once.
- mapping (bytes32 => bool) public transactions;
-
- // Address of current transaction signer
- address public currentContextAddress;
-
- /// @dev Executes an exchange method call in the context of signer.
- /// @param salt Arbitrary number to ensure uniqueness of transaction hash.
- /// @param signerAddress Address of transaction signer.
- /// @param data AbiV2 encoded calldata.
- /// @param signature Proof of signer transaction by signer.
- function executeTransaction(
- uint256 salt,
- address signerAddress,
- bytes data,
- bytes signature
- )
- external
- {
- // Prevent reentrancy
- require(
- currentContextAddress == address(0),
- "REENTRANCY_ILLEGAL"
- );
-
- bytes32 transactionHash = hashEIP712Message(hashZeroExTransaction(
- salt,
- signerAddress,
- data
- ));
-
- // Validate transaction has not been executed
- require(
- !transactions[transactionHash],
- "INVALID_TX_HASH"
- );
-
- // Transaction always valid if signer is sender of transaction
- if (signerAddress != msg.sender) {
- // Validate signature
- require(
- isValidSignature(
- transactionHash,
- signerAddress,
- signature
- ),
- "INVALID_TX_SIGNATURE"
- );
-
- // Set the current transaction signer
- currentContextAddress = signerAddress;
- }
-
- // Execute transaction
- transactions[transactionHash] = true;
- require(
- address(this).delegatecall(data),
- "FAILED_EXECUTION"
- );
-
- // Reset current transaction signer if it was previously updated
- if (signerAddress != msg.sender) {
- currentContextAddress = address(0);
- }
- }
-
- /// @dev Calculates EIP712 hash of the Transaction.
- /// @param salt Arbitrary number to ensure uniqueness of transaction hash.
- /// @param signerAddress Address of transaction signer.
- /// @param data AbiV2 encoded calldata.
- /// @return EIP712 hash of the Transaction.
- function hashZeroExTransaction(
- uint256 salt,
- address signerAddress,
- bytes memory data
- )
- internal
- pure
- returns (bytes32 result)
- {
- bytes32 schemaHash = EIP712_ZEROEX_TRANSACTION_SCHEMA_HASH;
- bytes32 dataHash = keccak256(data);
-
- // Assembly for more efficiently computing:
- // keccak256(abi.encodePacked(
- // EIP712_ZEROEX_TRANSACTION_SCHEMA_HASH,
- // salt,
- // bytes32(signerAddress),
- // keccak256(data)
- // ));
-
- assembly {
- // Load free memory pointer
- let memPtr := mload(64)
-
- mstore(memPtr, schemaHash) // hash of schema
- mstore(add(memPtr, 32), salt) // salt
- mstore(add(memPtr, 64), and(signerAddress, 0xffffffffffffffffffffffffffffffffffffffff)) // signerAddress
- mstore(add(memPtr, 96), dataHash) // hash of data
-
- // Compute hash
- result := keccak256(memPtr, 128)
- }
- return result;
- }
-
- /// @dev The current function will be called in the context of this address (either 0x transaction signer or `msg.sender`).
- /// If calling a fill function, this address will represent the taker.
- /// If calling a cancel function, this address will represent the maker.
- /// @return Signer of 0x transaction if entry point is `executeTransaction`.
- /// `msg.sender` if entry point is any other function.
- function getCurrentContextAddress()
- internal
- view
- returns (address)
- {
- address currentContextAddress_ = currentContextAddress;
- address contextAddress = currentContextAddress_ == address(0) ? msg.sender : currentContextAddress_;
- return contextAddress;
- }
-}
diff --git a/packages/contracts/contracts/protocol/Exchange/MixinWrapperFunctions.sol b/packages/contracts/contracts/protocol/Exchange/MixinWrapperFunctions.sol
deleted file mode 100644
index cddff0e5f..000000000
--- a/packages/contracts/contracts/protocol/Exchange/MixinWrapperFunctions.sol
+++ /dev/null
@@ -1,426 +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 "../../utils/ReentrancyGuard/ReentrancyGuard.sol";
-import "./libs/LibMath.sol";
-import "./libs/LibOrder.sol";
-import "./libs/LibFillResults.sol";
-import "./libs/LibAbiEncoder.sol";
-import "./mixins/MExchangeCore.sol";
-import "./mixins/MWrapperFunctions.sol";
-
-
-contract MixinWrapperFunctions is
- ReentrancyGuard,
- LibMath,
- LibFillResults,
- LibAbiEncoder,
- MExchangeCore,
- MWrapperFunctions
-{
- /// @dev Fills the input order. Reverts if exact takerAssetFillAmount not filled.
- /// @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.
- function fillOrKillOrder(
- LibOrder.Order memory order,
- uint256 takerAssetFillAmount,
- bytes memory signature
- )
- public
- nonReentrant
- returns (FillResults memory fillResults)
- {
- fillResults = fillOrKillOrderInternal(
- order,
- takerAssetFillAmount,
- signature
- );
- return fillResults;
- }
-
- /// @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
- )
- public
- returns (FillResults memory fillResults)
- {
- // ABI encode calldata for `fillOrder`
- bytes memory fillOrderCalldata = abiEncodeFillOrder(
- order,
- takerAssetFillAmount,
- signature
- );
-
- // Delegate to `fillOrder` and handle any exceptions gracefully
- assembly {
- let success := delegatecall(
- gas, // forward all gas
- address, // call address of this contract
- 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.
- /// @param orders Array of order specifications.
- /// @param takerAssetFillAmounts Array of desired amounts of takerAsset to sell in orders.
- /// @param signatures Proofs that orders have been created by makers.
- /// @return Amounts filled and fees paid by makers and taker.
- /// NOTE: makerAssetFilledAmount and takerAssetFilledAmount may include amounts filled of different assets.
- function batchFillOrders(
- LibOrder.Order[] memory orders,
- uint256[] memory takerAssetFillAmounts,
- bytes[] memory signatures
- )
- public
- nonReentrant
- returns (FillResults memory totalFillResults)
- {
- uint256 ordersLength = orders.length;
- for (uint256 i = 0; i != ordersLength; i++) {
- FillResults memory singleFillResults = fillOrderInternal(
- orders[i],
- takerAssetFillAmounts[i],
- signatures[i]
- );
- addFillResults(totalFillResults, singleFillResults);
- }
- return totalFillResults;
- }
-
- /// @dev Synchronously executes multiple calls of fillOrKill.
- /// @param orders Array of order specifications.
- /// @param takerAssetFillAmounts Array of desired amounts of takerAsset to sell in orders.
- /// @param signatures Proofs that orders have been created by makers.
- /// @return Amounts filled and fees paid by makers and taker.
- /// NOTE: makerAssetFilledAmount and takerAssetFilledAmount may include amounts filled of different assets.
- function batchFillOrKillOrders(
- LibOrder.Order[] memory orders,
- uint256[] memory takerAssetFillAmounts,
- bytes[] memory signatures
- )
- public
- nonReentrant
- returns (FillResults memory totalFillResults)
- {
- uint256 ordersLength = orders.length;
- for (uint256 i = 0; i != ordersLength; i++) {
- FillResults memory singleFillResults = fillOrKillOrderInternal(
- orders[i],
- takerAssetFillAmounts[i],
- signatures[i]
- );
- addFillResults(totalFillResults, singleFillResults);
- }
- return totalFillResults;
- }
-
- /// @dev Fills an order with specified parameters and ECDSA signature.
- /// Returns false if the transaction would otherwise revert.
- /// @param orders Array of order specifications.
- /// @param takerAssetFillAmounts Array of desired amounts of takerAsset to sell in orders.
- /// @param signatures Proofs that orders have been created by makers.
- /// @return Amounts filled and fees paid by makers and taker.
- /// NOTE: makerAssetFilledAmount and takerAssetFilledAmount may include amounts filled of different assets.
- function batchFillOrdersNoThrow(
- LibOrder.Order[] memory orders,
- uint256[] memory takerAssetFillAmounts,
- bytes[] memory signatures
- )
- public
- returns (FillResults memory totalFillResults)
- {
- uint256 ordersLength = orders.length;
- for (uint256 i = 0; i != ordersLength; i++) {
- FillResults memory singleFillResults = fillOrderNoThrow(
- orders[i],
- takerAssetFillAmounts[i],
- signatures[i]
- );
- addFillResults(totalFillResults, singleFillResults);
- }
- return totalFillResults;
- }
-
- /// @dev Synchronously executes multiple calls of fillOrder until total amount of takerAsset is sold by taker.
- /// @param orders Array of order specifications.
- /// @param takerAssetFillAmount Desired amount of takerAsset to sell.
- /// @param signatures Proofs that orders have been created by makers.
- /// @return Amounts filled and fees paid by makers and taker.
- function marketSellOrders(
- LibOrder.Order[] memory orders,
- uint256 takerAssetFillAmount,
- bytes[] memory signatures
- )
- public
- nonReentrant
- returns (FillResults memory totalFillResults)
- {
- bytes memory takerAssetData = orders[0].takerAssetData;
-
- uint256 ordersLength = orders.length;
- for (uint256 i = 0; i != ordersLength; i++) {
-
- // We assume that asset being sold by taker is the same for each order.
- // Rather than passing this in as calldata, we use the takerAssetData from the first order in all later orders.
- orders[i].takerAssetData = takerAssetData;
-
- // Calculate the remaining amount of takerAsset to sell
- uint256 remainingTakerAssetFillAmount = safeSub(takerAssetFillAmount, totalFillResults.takerAssetFilledAmount);
-
- // Attempt to sell the remaining amount of takerAsset
- FillResults memory singleFillResults = fillOrderInternal(
- 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 >= takerAssetFillAmount) {
- break;
- }
- }
- return totalFillResults;
- }
-
- /// @dev Synchronously executes multiple calls of fillOrder until total amount of takerAsset is sold by taker.
- /// Returns false if the transaction would otherwise revert.
- /// @param orders Array of order specifications.
- /// @param takerAssetFillAmount Desired amount of takerAsset to sell.
- /// @param signatures Proofs that orders have been signed by makers.
- /// @return Amounts filled and fees paid by makers and taker.
- function marketSellOrdersNoThrow(
- LibOrder.Order[] memory orders,
- uint256 takerAssetFillAmount,
- bytes[] memory signatures
- )
- public
- returns (FillResults memory totalFillResults)
- {
- bytes memory takerAssetData = orders[0].takerAssetData;
-
- uint256 ordersLength = orders.length;
- for (uint256 i = 0; i != ordersLength; i++) {
-
- // We assume that asset being sold by taker is the same for each order.
- // Rather than passing this in as calldata, we use the takerAssetData from the first order in all later orders.
- orders[i].takerAssetData = takerAssetData;
-
- // Calculate the remaining amount of takerAsset to sell
- uint256 remainingTakerAssetFillAmount = safeSub(takerAssetFillAmount, totalFillResults.takerAssetFilledAmount);
-
- // 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 takerAsset has been sold
- if (totalFillResults.takerAssetFilledAmount >= takerAssetFillAmount) {
- break;
- }
- }
- return totalFillResults;
- }
-
- /// @dev Synchronously executes multiple calls of fillOrder until total amount of makerAsset is bought by taker.
- /// @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 marketBuyOrders(
- LibOrder.Order[] memory orders,
- uint256 makerAssetFillAmount,
- bytes[] memory signatures
- )
- public
- nonReentrant
- returns (FillResults memory totalFillResults)
- {
- bytes memory makerAssetData = orders[0].makerAssetData;
-
- 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.
- // Rather than passing this in as calldata, we copy the makerAssetData from the first order onto all later orders.
- orders[i].makerAssetData = makerAssetData;
-
- // 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
- uint256 remainingTakerAssetFillAmount = getPartialAmountFloor(
- orders[i].takerAssetAmount,
- orders[i].makerAssetAmount,
- remainingMakerAssetFillAmount
- );
-
- // Attempt to sell the remaining amount of takerAsset
- FillResults memory singleFillResults = fillOrderInternal(
- 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
- if (totalFillResults.makerAssetFilledAmount >= makerAssetFillAmount) {
- 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.
- /// @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 marketBuyOrdersNoThrow(
- LibOrder.Order[] memory orders,
- uint256 makerAssetFillAmount,
- bytes[] memory signatures
- )
- public
- returns (FillResults memory totalFillResults)
- {
- bytes memory makerAssetData = orders[0].makerAssetData;
-
- 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.
- // Rather than passing this in as calldata, we copy the makerAssetData from the first order onto all later orders.
- orders[i].makerAssetData = makerAssetData;
-
- // 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
- uint256 remainingTakerAssetFillAmount = getPartialAmountFloor(
- 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
- if (totalFillResults.makerAssetFilledAmount >= makerAssetFillAmount) {
- break;
- }
- }
- return totalFillResults;
- }
-
- /// @dev Synchronously cancels multiple orders in a single transaction.
- /// @param orders Array of order specifications.
- function batchCancelOrders(LibOrder.Order[] memory orders)
- public
- nonReentrant
- {
- uint256 ordersLength = orders.length;
- for (uint256 i = 0; i != ordersLength; i++) {
- cancelOrderInternal(orders[i]);
- }
- }
-
- /// @dev Fetches information for all passed in orders.
- /// @param orders Array of order specifications.
- /// @return Array of OrderInfo instances that correspond to each order.
- function getOrdersInfo(LibOrder.Order[] memory orders)
- public
- view
- returns (LibOrder.OrderInfo[] memory)
- {
- uint256 ordersLength = orders.length;
- LibOrder.OrderInfo[] memory ordersInfo = new LibOrder.OrderInfo[](ordersLength);
- for (uint256 i = 0; i != ordersLength; i++) {
- ordersInfo[i] = getOrderInfo(orders[i]);
- }
- return ordersInfo;
- }
-
- /// @dev Fills the input order. Reverts if exact takerAssetFillAmount not filled.
- /// @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.
- function fillOrKillOrderInternal(
- LibOrder.Order memory order,
- uint256 takerAssetFillAmount,
- bytes memory signature
- )
- internal
- returns (FillResults memory fillResults)
- {
- fillResults = fillOrderInternal(
- order,
- takerAssetFillAmount,
- signature
- );
- require(
- fillResults.takerAssetFilledAmount == takerAssetFillAmount,
- "COMPLETE_FILL_FAILED"
- );
- return fillResults;
- }
-}
diff --git a/packages/contracts/contracts/protocol/Exchange/interfaces/IAssetProxyDispatcher.sol b/packages/contracts/contracts/protocol/Exchange/interfaces/IAssetProxyDispatcher.sol
deleted file mode 100644
index 8db8d6f6c..000000000
--- a/packages/contracts/contracts/protocol/Exchange/interfaces/IAssetProxyDispatcher.sol
+++ /dev/null
@@ -1,37 +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 IAssetProxyDispatcher {
-
- /// @dev Registers an asset proxy to its asset proxy id.
- /// Once an asset proxy is registered, it cannot be unregistered.
- /// @param assetProxy Address of new asset proxy to register.
- function registerAssetProxy(address assetProxy)
- external;
-
- /// @dev Gets an asset proxy.
- /// @param assetProxyId Id of the asset proxy.
- /// @return The asset proxy registered to assetProxyId. Returns 0x0 if no proxy is registered.
- function getAssetProxy(bytes4 assetProxyId)
- external
- view
- returns (address);
-}
diff --git a/packages/contracts/contracts/protocol/Exchange/interfaces/IExchange.sol b/packages/contracts/contracts/protocol/Exchange/interfaces/IExchange.sol
deleted file mode 100644
index b92abba04..000000000
--- a/packages/contracts/contracts/protocol/Exchange/interfaces/IExchange.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 "./IExchangeCore.sol";
-import "./IMatchOrders.sol";
-import "./ISignatureValidator.sol";
-import "./ITransactions.sol";
-import "./IAssetProxyDispatcher.sol";
-import "./IWrapperFunctions.sol";
-
-
-// solhint-disable no-empty-blocks
-contract IExchange is
- IExchangeCore,
- IMatchOrders,
- ISignatureValidator,
- ITransactions,
- IAssetProxyDispatcher,
- IWrapperFunctions
-{}
diff --git a/packages/contracts/contracts/protocol/Exchange/interfaces/IExchangeCore.sol b/packages/contracts/contracts/protocol/Exchange/interfaces/IExchangeCore.sol
deleted file mode 100644
index 9995e0385..000000000
--- a/packages/contracts/contracts/protocol/Exchange/interfaces/IExchangeCore.sol
+++ /dev/null
@@ -1,60 +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/LibOrder.sol";
-import "../libs/LibFillResults.sol";
-
-
-contract IExchangeCore {
-
- /// @dev Cancels all orders created by makerAddress with a salt less than or equal to the targetOrderEpoch
- /// and senderAddress equal to msg.sender (or null address if msg.sender == makerAddress).
- /// @param targetOrderEpoch Orders created with a salt less or equal to this value will be cancelled.
- function cancelOrdersUpTo(uint256 targetOrderEpoch)
- external;
-
- /// @dev Fills the input order.
- /// @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 fillOrder(
- LibOrder.Order memory order,
- uint256 takerAssetFillAmount,
- bytes memory signature
- )
- public
- returns (LibFillResults.FillResults memory fillResults);
-
- /// @dev After calling, the order can not be filled anymore.
- /// @param order Order struct containing order specifications.
- function cancelOrder(LibOrder.Order memory order)
- public;
-
- /// @dev Gets information about an order: status, hash, and amount filled.
- /// @param order Order to gather information on.
- /// @return OrderInfo Information about the order and its state.
- /// See LibOrder.OrderInfo for a complete description.
- function getOrderInfo(LibOrder.Order memory order)
- public
- view
- returns (LibOrder.OrderInfo memory orderInfo);
-}
diff --git a/packages/contracts/contracts/protocol/Exchange/interfaces/IMatchOrders.sol b/packages/contracts/contracts/protocol/Exchange/interfaces/IMatchOrders.sol
deleted file mode 100644
index 73447f3ae..000000000
--- a/packages/contracts/contracts/protocol/Exchange/interfaces/IMatchOrders.sol
+++ /dev/null
@@ -1,44 +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/LibOrder.sol";
-import "../libs/LibFillResults.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 goes to the taker (who matched the two orders).
- /// @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.
- /// @return matchedFillResults Amounts filled and fees paid by maker and taker of matched orders.
- function matchOrders(
- LibOrder.Order memory leftOrder,
- LibOrder.Order memory rightOrder,
- bytes memory leftSignature,
- bytes memory rightSignature
- )
- public
- returns (LibFillResults.MatchedFillResults memory matchedFillResults);
-}
diff --git a/packages/contracts/contracts/protocol/Exchange/interfaces/ISignatureValidator.sol b/packages/contracts/contracts/protocol/Exchange/interfaces/ISignatureValidator.sol
deleted file mode 100644
index 1fd0eccf0..000000000
--- a/packages/contracts/contracts/protocol/Exchange/interfaces/ISignatureValidator.sol
+++ /dev/null
@@ -1,57 +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 ISignatureValidator {
-
- /// @dev Approves a hash on-chain using any valid signature type.
- /// After presigning a hash, the preSign signature type will become valid for that hash and signer.
- /// @param signerAddress Address that should have signed the given hash.
- /// @param signature Proof that the hash has been signed by signer.
- function preSign(
- bytes32 hash,
- address signerAddress,
- bytes signature
- )
- external;
-
- /// @dev Approves/unnapproves a Validator contract to verify signatures on signer's behalf.
- /// @param validatorAddress Address of Validator contract.
- /// @param approval Approval or disapproval of Validator contract.
- function setSignatureValidatorApproval(
- address validatorAddress,
- bool approval
- )
- external;
-
- /// @dev Verifies that a signature is valid.
- /// @param hash Message hash that is signed.
- /// @param signerAddress Address of signer.
- /// @param signature Proof of signing.
- /// @return Validity of order signature.
- function isValidSignature(
- bytes32 hash,
- address signerAddress,
- bytes memory signature
- )
- public
- view
- returns (bool isValid);
-}
diff --git a/packages/contracts/contracts/protocol/Exchange/interfaces/ITransactions.sol b/packages/contracts/contracts/protocol/Exchange/interfaces/ITransactions.sol
deleted file mode 100644
index 4446c55ce..000000000
--- a/packages/contracts/contracts/protocol/Exchange/interfaces/ITransactions.sol
+++ /dev/null
@@ -1,35 +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 ITransactions {
-
- /// @dev Executes an exchange method call in the context of signer.
- /// @param salt Arbitrary number to ensure uniqueness of transaction hash.
- /// @param signerAddress Address of transaction signer.
- /// @param data AbiV2 encoded calldata.
- /// @param signature Proof of signer transaction by signer.
- function executeTransaction(
- uint256 salt,
- address signerAddress,
- bytes data,
- bytes signature
- )
- external;
-}
diff --git a/packages/contracts/contracts/protocol/Exchange/interfaces/IValidator.sol b/packages/contracts/contracts/protocol/Exchange/interfaces/IValidator.sol
deleted file mode 100644
index 2dd69100c..000000000
--- a/packages/contracts/contracts/protocol/Exchange/interfaces/IValidator.sol
+++ /dev/null
@@ -1,37 +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 IValidator {
-
- /// @dev Verifies that a signature is valid.
- /// @param hash Message hash that is signed.
- /// @param signerAddress Address that should have signed the given hash.
- /// @param signature Proof of signing.
- /// @return Validity of order signature.
- function isValidSignature(
- bytes32 hash,
- address signerAddress,
- bytes signature
- )
- external
- view
- returns (bool isValid);
-}
diff --git a/packages/contracts/contracts/protocol/Exchange/interfaces/IWallet.sol b/packages/contracts/contracts/protocol/Exchange/interfaces/IWallet.sol
deleted file mode 100644
index c97161ca6..000000000
--- a/packages/contracts/contracts/protocol/Exchange/interfaces/IWallet.sol
+++ /dev/null
@@ -1,35 +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 IWallet {
-
- /// @dev Verifies that a signature is valid.
- /// @param hash Message hash that is signed.
- /// @param signature Proof of signing.
- /// @return Validity of order signature.
- function isValidSignature(
- bytes32 hash,
- bytes signature
- )
- external
- view
- returns (bool isValid);
-}
diff --git a/packages/contracts/contracts/protocol/Exchange/interfaces/IWrapperFunctions.sol b/packages/contracts/contracts/protocol/Exchange/interfaces/IWrapperFunctions.sol
deleted file mode 100644
index 56a533646..000000000
--- a/packages/contracts/contracts/protocol/Exchange/interfaces/IWrapperFunctions.sol
+++ /dev/null
@@ -1,160 +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/LibOrder.sol";
-import "../libs/LibFillResults.sol";
-
-
-contract IWrapperFunctions {
-
- /// @dev Fills the input order. Reverts if exact takerAssetFillAmount not filled.
- /// @param order LibOrder.Order struct containing order specifications.
- /// @param takerAssetFillAmount Desired amount of takerAsset to sell.
- /// @param signature Proof that order has been created by maker.
- function fillOrKillOrder(
- LibOrder.Order memory order,
- uint256 takerAssetFillAmount,
- bytes memory signature
- )
- public
- returns (LibFillResults.FillResults memory fillResults);
-
- /// @dev Fills an order with specified parameters and ECDSA signature.
- /// Returns false if the transaction would otherwise revert.
- /// @param order LibOrder.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
- )
- public
- returns (LibFillResults.FillResults memory fillResults);
-
- /// @dev Synchronously executes multiple calls of fillOrder.
- /// @param orders Array of order specifications.
- /// @param takerAssetFillAmounts Array of desired amounts of takerAsset to sell in orders.
- /// @param signatures Proofs that orders have been created by makers.
- /// @return Amounts filled and fees paid by makers and taker.
- function batchFillOrders(
- LibOrder.Order[] memory orders,
- uint256[] memory takerAssetFillAmounts,
- bytes[] memory signatures
- )
- public
- returns (LibFillResults.FillResults memory totalFillResults);
-
- /// @dev Synchronously executes multiple calls of fillOrKill.
- /// @param orders Array of order specifications.
- /// @param takerAssetFillAmounts Array of desired amounts of takerAsset to sell in orders.
- /// @param signatures Proofs that orders have been created by makers.
- /// @return Amounts filled and fees paid by makers and taker.
- function batchFillOrKillOrders(
- LibOrder.Order[] memory orders,
- uint256[] memory takerAssetFillAmounts,
- bytes[] memory signatures
- )
- public
- returns (LibFillResults.FillResults memory totalFillResults);
-
- /// @dev Fills an order with specified parameters and ECDSA signature.
- /// Returns false if the transaction would otherwise revert.
- /// @param orders Array of order specifications.
- /// @param takerAssetFillAmounts Array of desired amounts of takerAsset to sell in orders.
- /// @param signatures Proofs that orders have been created by makers.
- /// @return Amounts filled and fees paid by makers and taker.
- function batchFillOrdersNoThrow(
- LibOrder.Order[] memory orders,
- uint256[] memory takerAssetFillAmounts,
- bytes[] memory signatures
- )
- public
- returns (LibFillResults.FillResults memory totalFillResults);
-
- /// @dev Synchronously executes multiple calls of fillOrder until total amount of takerAsset is sold by taker.
- /// @param orders Array of order specifications.
- /// @param takerAssetFillAmount Desired amount of takerAsset to sell.
- /// @param signatures Proofs that orders have been created by makers.
- /// @return Amounts filled and fees paid by makers and taker.
- function marketSellOrders(
- LibOrder.Order[] memory orders,
- uint256 takerAssetFillAmount,
- bytes[] memory signatures
- )
- public
- returns (LibFillResults.FillResults memory totalFillResults);
-
- /// @dev Synchronously executes multiple calls of fillOrder until total amount of takerAsset is sold by taker.
- /// Returns false if the transaction would otherwise revert.
- /// @param orders Array of order specifications.
- /// @param takerAssetFillAmount Desired amount of takerAsset to sell.
- /// @param signatures Proofs that orders have been signed by makers.
- /// @return Amounts filled and fees paid by makers and taker.
- function marketSellOrdersNoThrow(
- LibOrder.Order[] memory orders,
- uint256 takerAssetFillAmount,
- bytes[] memory signatures
- )
- public
- returns (LibFillResults.FillResults memory totalFillResults);
-
- /// @dev Synchronously executes multiple calls of fillOrder until total amount of makerAsset is bought by taker.
- /// @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 marketBuyOrders(
- LibOrder.Order[] memory orders,
- uint256 makerAssetFillAmount,
- bytes[] memory signatures
- )
- public
- 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.
- /// @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 marketBuyOrdersNoThrow(
- LibOrder.Order[] memory orders,
- uint256 makerAssetFillAmount,
- bytes[] memory signatures
- )
- public
- returns (LibFillResults.FillResults memory totalFillResults);
-
- /// @dev Synchronously cancels multiple orders in a single transaction.
- /// @param orders Array of order specifications.
- function batchCancelOrders(LibOrder.Order[] memory orders)
- public;
-
- /// @dev Fetches information for all passed in orders
- /// @param orders Array of order specifications.
- /// @return Array of OrderInfo instances that correspond to each order.
- function getOrdersInfo(LibOrder.Order[] memory orders)
- public
- view
- returns (LibOrder.OrderInfo[] memory);
-}
diff --git a/packages/contracts/contracts/protocol/Exchange/libs/LibAbiEncoder.sol b/packages/contracts/contracts/protocol/Exchange/libs/LibAbiEncoder.sol
deleted file mode 100644
index 4aad37709..000000000
--- a/packages/contracts/contracts/protocol/Exchange/libs/LibAbiEncoder.sol
+++ /dev/null
@@ -1,215 +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 "./LibOrder.sol";
-
-
-contract LibAbiEncoder {
-
- /// @dev ABI encodes calldata for `fillOrder`.
- /// @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 ABI encoded calldata for `fillOrder`.
- function abiEncodeFillOrder(
- LibOrder.Order memory order,
- uint256 takerAssetFillAmount,
- bytes memory signature
- )
- internal
- pure
- returns (bytes memory fillOrderCalldata)
- {
- // We need to call MExchangeCore.fillOrder using a delegatecall in
- // assembly so that we can intercept a call that throws. For this, we
- // need the input encoded in memory in the Ethereum ABIv2 format [1].
-
- // | Area | Offset | Length | Contents |
- // | -------- |--------|---------|-------------------------------------------- |
- // | Header | 0x00 | 4 | function selector |
- // | Params | | 3 * 32 | function parameters: |
- // | | 0x00 | | 1. offset to order (*) |
- // | | 0x20 | | 2. takerAssetFillAmount |
- // | | 0x40 | | 3. offset to signature (*) |
- // | Data | | 12 * 32 | order: |
- // | | 0x000 | | 1. senderAddress |
- // | | 0x020 | | 2. makerAddress |
- // | | 0x040 | | 3. takerAddress |
- // | | 0x060 | | 4. feeRecipientAddress |
- // | | 0x080 | | 5. makerAssetAmount |
- // | | 0x0A0 | | 6. takerAssetAmount |
- // | | 0x0C0 | | 7. makerFeeAmount |
- // | | 0x0E0 | | 8. takerFeeAmount |
- // | | 0x100 | | 9. expirationTimeSeconds |
- // | | 0x120 | | 10. salt |
- // | | 0x140 | | 11. Offset to makerAssetData (*) |
- // | | 0x160 | | 12. Offset to takerAssetData (*) |
- // | | 0x180 | 32 | makerAssetData Length |
- // | | 0x1A0 | ** | makerAssetData Contents |
- // | | 0x1C0 | 32 | takerAssetData Length |
- // | | 0x1E0 | ** | takerAssetData Contents |
- // | | 0x200 | 32 | signature Length |
- // | | 0x220 | ** | signature Contents |
-
- // * Offsets are calculated from the beginning of the current area: Header, Params, Data:
- // An offset stored in the Params area is calculated from the beginning of the Params section.
- // An offset stored in the Data area is calculated from the beginning of the Data section.
-
- // ** The length of dynamic array contents are stored in the field immediately preceeding the contents.
-
- // [1]: https://solidity.readthedocs.io/en/develop/abi-spec.html
-
- assembly {
-
- // Areas below may use the following variables:
- // 1. <area>Start -- Start of this area in memory
- // 2. <area>End -- End of this area in memory. This value may
- // be precomputed (before writing contents),
- // or it may be computed as contents are written.
- // 3. <area>Offset -- Current offset into area. If an area's End
- // is precomputed, this variable tracks the
- // offsets of contents as they are written.
-
- /////// Setup Header Area ///////
- // Load free memory pointer
- fillOrderCalldata := mload(0x40)
- // bytes4(keccak256("fillOrder((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),uint256,bytes)"))
- // = 0xb4be83d5
- // Leave 0x20 bytes to store the length
- mstore(add(fillOrderCalldata, 0x20), 0xb4be83d500000000000000000000000000000000000000000000000000000000)
- let headerAreaEnd := add(fillOrderCalldata, 0x24)
-
- /////// Setup Params Area ///////
- // This area is preallocated and written to later.
- // This is because we need to fill in offsets that have not yet been calculated.
- let paramsAreaStart := headerAreaEnd
- let paramsAreaEnd := add(paramsAreaStart, 0x60)
- let paramsAreaOffset := paramsAreaStart
-
- /////// Setup Data Area ///////
- let dataAreaStart := paramsAreaEnd
- let dataAreaEnd := dataAreaStart
-
- // Offset from the source data we're reading from
- let sourceOffset := order
- // arrayLenBytes and arrayLenWords track the length of a dynamically-allocated bytes array.
- let arrayLenBytes := 0
- let arrayLenWords := 0
-
- /////// Write order Struct ///////
- // Write memory location of Order, relative to the start of the
- // parameter list, then increment the paramsAreaOffset respectively.
- mstore(paramsAreaOffset, sub(dataAreaEnd, paramsAreaStart))
- paramsAreaOffset := add(paramsAreaOffset, 0x20)
-
- // Write values for each field in the order
- // It would be nice to use a loop, but we save on gas by writing
- // the stores sequentially.
- mstore(dataAreaEnd, mload(sourceOffset)) // makerAddress
- mstore(add(dataAreaEnd, 0x20), mload(add(sourceOffset, 0x20))) // takerAddress
- mstore(add(dataAreaEnd, 0x40), mload(add(sourceOffset, 0x40))) // feeRecipientAddress
- mstore(add(dataAreaEnd, 0x60), mload(add(sourceOffset, 0x60))) // senderAddress
- mstore(add(dataAreaEnd, 0x80), mload(add(sourceOffset, 0x80))) // makerAssetAmount
- mstore(add(dataAreaEnd, 0xA0), mload(add(sourceOffset, 0xA0))) // takerAssetAmount
- mstore(add(dataAreaEnd, 0xC0), mload(add(sourceOffset, 0xC0))) // makerFeeAmount
- mstore(add(dataAreaEnd, 0xE0), mload(add(sourceOffset, 0xE0))) // takerFeeAmount
- mstore(add(dataAreaEnd, 0x100), mload(add(sourceOffset, 0x100))) // expirationTimeSeconds
- mstore(add(dataAreaEnd, 0x120), mload(add(sourceOffset, 0x120))) // salt
- mstore(add(dataAreaEnd, 0x140), mload(add(sourceOffset, 0x140))) // Offset to makerAssetData
- mstore(add(dataAreaEnd, 0x160), mload(add(sourceOffset, 0x160))) // Offset to takerAssetData
- dataAreaEnd := add(dataAreaEnd, 0x180)
- sourceOffset := add(sourceOffset, 0x180)
-
- // Write offset to <order.makerAssetData>
- mstore(add(dataAreaStart, mul(10, 0x20)), sub(dataAreaEnd, dataAreaStart))
-
- // Calculate length of <order.makerAssetData>
- sourceOffset := mload(add(order, 0x140)) // makerAssetData
- arrayLenBytes := mload(sourceOffset)
- sourceOffset := add(sourceOffset, 0x20)
- arrayLenWords := div(add(arrayLenBytes, 0x1F), 0x20)
-
- // Write length of <order.makerAssetData>
- mstore(dataAreaEnd, arrayLenBytes)
- dataAreaEnd := add(dataAreaEnd, 0x20)
-
- // Write contents of <order.makerAssetData>
- for {let i := 0} lt(i, arrayLenWords) {i := add(i, 1)} {
- mstore(dataAreaEnd, mload(sourceOffset))
- dataAreaEnd := add(dataAreaEnd, 0x20)
- sourceOffset := add(sourceOffset, 0x20)
- }
-
- // Write offset to <order.takerAssetData>
- mstore(add(dataAreaStart, mul(11, 0x20)), sub(dataAreaEnd, dataAreaStart))
-
- // Calculate length of <order.takerAssetData>
- sourceOffset := mload(add(order, 0x160)) // takerAssetData
- arrayLenBytes := mload(sourceOffset)
- sourceOffset := add(sourceOffset, 0x20)
- arrayLenWords := div(add(arrayLenBytes, 0x1F), 0x20)
-
- // Write length of <order.takerAssetData>
- mstore(dataAreaEnd, arrayLenBytes)
- dataAreaEnd := add(dataAreaEnd, 0x20)
-
- // Write contents of <order.takerAssetData>
- for {let i := 0} lt(i, arrayLenWords) {i := add(i, 1)} {
- mstore(dataAreaEnd, mload(sourceOffset))
- dataAreaEnd := add(dataAreaEnd, 0x20)
- sourceOffset := add(sourceOffset, 0x20)
- }
-
- /////// Write takerAssetFillAmount ///////
- mstore(paramsAreaOffset, takerAssetFillAmount)
- paramsAreaOffset := add(paramsAreaOffset, 0x20)
-
- /////// Write signature ///////
- // Write offset to paramsArea
- mstore(paramsAreaOffset, sub(dataAreaEnd, paramsAreaStart))
-
- // Calculate length of signature
- sourceOffset := signature
- arrayLenBytes := mload(sourceOffset)
- sourceOffset := add(sourceOffset, 0x20)
- arrayLenWords := div(add(arrayLenBytes, 0x1F), 0x20)
-
- // Write length of signature
- mstore(dataAreaEnd, arrayLenBytes)
- dataAreaEnd := add(dataAreaEnd, 0x20)
-
- // Write contents of signature
- for {let i := 0} lt(i, arrayLenWords) {i := add(i, 1)} {
- mstore(dataAreaEnd, mload(sourceOffset))
- dataAreaEnd := add(dataAreaEnd, 0x20)
- sourceOffset := add(sourceOffset, 0x20)
- }
-
- // Set length of calldata
- mstore(fillOrderCalldata, sub(dataAreaEnd, add(fillOrderCalldata, 0x20)))
-
- // Increment free memory pointer
- mstore(0x40, dataAreaEnd)
- }
-
- return fillOrderCalldata;
- }
-}
diff --git a/packages/contracts/contracts/protocol/Exchange/libs/LibConstants.sol b/packages/contracts/contracts/protocol/Exchange/libs/LibConstants.sol
deleted file mode 100644
index 8d2732cd3..000000000
--- a/packages/contracts/contracts/protocol/Exchange/libs/LibConstants.sol
+++ /dev/null
@@ -1,49 +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;
-
-
-// solhint-disable max-line-length
-contract LibConstants {
-
- // Asset data for ZRX token. Used for fee transfers.
- // @TODO: Hardcode constant when we deploy. Currently
- // not constant to make testing easier.
-
- // The proxyId for ZRX_ASSET_DATA is bytes4(keccak256("ERC20Token(address)")) = 0xf47261b0
-
- // Kovan ZRX address is 0x6ff6c0ff1d68b964901f986d4c9fa3ac68346570.
- // The ABI encoded proxyId and address is 0xf47261b00000000000000000000000006ff6c0ff1d68b964901f986d4c9fa3ac68346570
- // bytes constant public ZRX_ASSET_DATA = "\xf4\x72\x61\xb0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x6f\xf6\xc0\xff\x1d\x68\xb9\x64\x90\x1f\x98\x6d\x4c\x9f\xa3\xac\x68\x34\x65\x70";
-
- // Mainnet ZRX address is 0xe41d2489571d322189246dafa5ebde1f4699f498.
- // The ABI encoded proxyId and address is 0xf47261b0000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f498
- // bytes constant public ZRX_ASSET_DATA = "\xf4\x72\x61\xb0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe4\x1d\x24\x89\x57\x1d\x32\x21\x89\x24\x6d\xaf\xa5\xeb\xde\x1f\x46\x99\xf4\x98";
-
- // solhint-disable-next-line var-name-mixedcase
- bytes public ZRX_ASSET_DATA;
-
- // @TODO: Remove when we deploy.
- constructor (bytes memory zrxAssetData)
- public
- {
- ZRX_ASSET_DATA = zrxAssetData;
- }
-}
-// solhint-enable max-line-length
diff --git a/packages/contracts/contracts/protocol/Exchange/libs/LibEIP712.sol b/packages/contracts/contracts/protocol/Exchange/libs/LibEIP712.sol
deleted file mode 100644
index 203edc1fd..000000000
--- a/packages/contracts/contracts/protocol/Exchange/libs/LibEIP712.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;
-
-
-contract LibEIP712 {
-
- // EIP191 header for EIP712 prefix
- string constant internal EIP191_HEADER = "\x19\x01";
-
- // EIP712 Domain Name value
- string constant internal EIP712_DOMAIN_NAME = "0x Protocol";
-
- // EIP712 Domain Version value
- string constant internal EIP712_DOMAIN_VERSION = "2";
-
- // Hash of the EIP712 Domain Separator Schema
- bytes32 constant internal EIP712_DOMAIN_SEPARATOR_SCHEMA_HASH = keccak256(abi.encodePacked(
- "EIP712Domain(",
- "string name,",
- "string version,",
- "address verifyingContract",
- ")"
- ));
-
- // Hash of the EIP712 Domain Separator data
- // solhint-disable-next-line var-name-mixedcase
- bytes32 public EIP712_DOMAIN_HASH;
-
- constructor ()
- public
- {
- EIP712_DOMAIN_HASH = keccak256(abi.encodePacked(
- EIP712_DOMAIN_SEPARATOR_SCHEMA_HASH,
- keccak256(bytes(EIP712_DOMAIN_NAME)),
- keccak256(bytes(EIP712_DOMAIN_VERSION)),
- bytes32(address(this))
- ));
- }
-
- /// @dev Calculates EIP712 encoding for a hash struct in this EIP712 Domain.
- /// @param hashStruct The EIP712 hash struct.
- /// @return EIP712 hash applied to this EIP712 Domain.
- function hashEIP712Message(bytes32 hashStruct)
- internal
- view
- returns (bytes32 result)
- {
- bytes32 eip712DomainHash = EIP712_DOMAIN_HASH;
-
- // Assembly for more efficient computing:
- // keccak256(abi.encodePacked(
- // EIP191_HEADER,
- // EIP712_DOMAIN_HASH,
- // hashStruct
- // ));
-
- assembly {
- // Load free memory pointer
- let memPtr := mload(64)
-
- mstore(memPtr, 0x1901000000000000000000000000000000000000000000000000000000000000) // EIP191 header
- mstore(add(memPtr, 2), eip712DomainHash) // EIP712 domain hash
- mstore(add(memPtr, 34), hashStruct) // Hash of struct
-
- // Compute hash
- result := keccak256(memPtr, 66)
- }
- return result;
- }
-}
diff --git a/packages/contracts/contracts/protocol/Exchange/libs/LibExchangeErrors.sol b/packages/contracts/contracts/protocol/Exchange/libs/LibExchangeErrors.sol
deleted file mode 100644
index a0f75bc06..000000000
--- a/packages/contracts/contracts/protocol/Exchange/libs/LibExchangeErrors.sol
+++ /dev/null
@@ -1,70 +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;
-
-
-/// @dev This contract documents the revert reasons used in the Exchange contract.
-/// This contract is intended to serve as a reference, but is not actually used for efficiency reasons.
-contract LibExchangeErrors {
-
- /// Order validation errors ///
- string constant ORDER_UNFILLABLE = "ORDER_UNFILLABLE"; // Order cannot be filled.
- string constant INVALID_MAKER = "INVALID_MAKER"; // Invalid makerAddress.
- string constant INVALID_TAKER = "INVALID_TAKER"; // Invalid takerAddress.
- string constant INVALID_SENDER = "INVALID_SENDER"; // Invalid `msg.sender`.
- string constant INVALID_ORDER_SIGNATURE = "INVALID_ORDER_SIGNATURE"; // Signature validation failed.
-
- /// fillOrder validation errors ///
- string constant INVALID_TAKER_AMOUNT = "INVALID_TAKER_AMOUNT"; // takerAssetFillAmount cannot equal 0.
- string constant ROUNDING_ERROR = "ROUNDING_ERROR"; // Rounding error greater than 0.1% of takerAssetFillAmount.
-
- /// Signature validation errors ///
- string constant INVALID_SIGNATURE = "INVALID_SIGNATURE"; // Signature validation failed.
- string constant SIGNATURE_ILLEGAL = "SIGNATURE_ILLEGAL"; // Signature type is illegal.
- string constant SIGNATURE_UNSUPPORTED = "SIGNATURE_UNSUPPORTED"; // Signature type unsupported.
-
- /// cancelOrdersUptTo errors ///
- string constant INVALID_NEW_ORDER_EPOCH = "INVALID_NEW_ORDER_EPOCH"; // Specified salt must be greater than or equal to existing orderEpoch.
-
- /// fillOrKillOrder errors ///
- string constant COMPLETE_FILL_FAILED = "COMPLETE_FILL_FAILED"; // Desired takerAssetFillAmount could not be completely filled.
-
- /// matchOrders errors ///
- string constant NEGATIVE_SPREAD_REQUIRED = "NEGATIVE_SPREAD_REQUIRED"; // Matched orders must have a negative spread.
-
- /// Transaction errors ///
- string constant REENTRANCY_ILLEGAL = "REENTRANCY_ILLEGAL"; // Recursive reentrancy is not allowed.
- string constant INVALID_TX_HASH = "INVALID_TX_HASH"; // Transaction has already been executed.
- string constant INVALID_TX_SIGNATURE = "INVALID_TX_SIGNATURE"; // Signature validation failed.
- string constant FAILED_EXECUTION = "FAILED_EXECUTION"; // Transaction execution failed.
-
- /// registerAssetProxy errors ///
- string constant ASSET_PROXY_ALREADY_EXISTS = "ASSET_PROXY_ALREADY_EXISTS"; // AssetProxy with same id already exists.
-
- /// dispatchTransferFrom errors ///
- string constant ASSET_PROXY_DOES_NOT_EXIST = "ASSET_PROXY_DOES_NOT_EXIST"; // No assetProxy registered at given id.
- string constant TRANSFER_FAILED = "TRANSFER_FAILED"; // Asset transfer unsuccesful.
-
- /// Length validation errors ///
- string constant LENGTH_GREATER_THAN_0_REQUIRED = "LENGTH_GREATER_THAN_0_REQUIRED"; // Byte array must have a length greater than 0.
- string constant LENGTH_GREATER_THAN_3_REQUIRED = "LENGTH_GREATER_THAN_3_REQUIRED"; // Byte array must have a length greater than 3.
- string constant LENGTH_0_REQUIRED = "LENGTH_0_REQUIRED"; // Byte array must have a length of 0.
- string constant LENGTH_65_REQUIRED = "LENGTH_65_REQUIRED"; // Byte array must have a length of 65.
-}
diff --git a/packages/contracts/contracts/protocol/Exchange/libs/LibFillResults.sol b/packages/contracts/contracts/protocol/Exchange/libs/LibFillResults.sol
deleted file mode 100644
index 659ae9a69..000000000
--- a/packages/contracts/contracts/protocol/Exchange/libs/LibFillResults.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 "../../../utils/SafeMath/SafeMath.sol";
-
-
-contract LibFillResults is
- SafeMath
-{
- struct FillResults {
- uint256 makerAssetFilledAmount; // Total amount of makerAsset(s) filled.
- uint256 takerAssetFilledAmount; // Total amount of takerAsset(s) filled.
- uint256 makerFeePaid; // Total amount of ZRX paid by maker(s) to feeRecipient(s).
- uint256 takerFeePaid; // Total amount of ZRX paid by taker to feeRecipients(s).
- }
-
- struct MatchedFillResults {
- FillResults left; // Amounts filled and fees paid of left order.
- FillResults right; // Amounts filled and fees paid of right order.
- uint256 leftMakerAssetSpreadAmount; // Spread between price of left and right order, denominated in the left order's makerAsset, paid to taker.
- }
-
- /// @dev Adds properties of both FillResults instances.
- /// Modifies the first FillResults instance specified.
- /// @param totalFillResults Fill results instance that will be added onto.
- /// @param singleFillResults Fill results instance that will be added to totalFillResults.
- function addFillResults(FillResults memory totalFillResults, FillResults memory singleFillResults)
- internal
- pure
- {
- totalFillResults.makerAssetFilledAmount = safeAdd(totalFillResults.makerAssetFilledAmount, singleFillResults.makerAssetFilledAmount);
- totalFillResults.takerAssetFilledAmount = safeAdd(totalFillResults.takerAssetFilledAmount, singleFillResults.takerAssetFilledAmount);
- totalFillResults.makerFeePaid = safeAdd(totalFillResults.makerFeePaid, singleFillResults.makerFeePaid);
- totalFillResults.takerFeePaid = safeAdd(totalFillResults.takerFeePaid, singleFillResults.takerFeePaid);
- }
-}
diff --git a/packages/contracts/contracts/protocol/Exchange/libs/LibMath.sol b/packages/contracts/contracts/protocol/Exchange/libs/LibMath.sol
deleted file mode 100644
index c0b85ea10..000000000
--- a/packages/contracts/contracts/protocol/Exchange/libs/LibMath.sol
+++ /dev/null
@@ -1,253 +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 "../../../utils/SafeMath/SafeMath.sol";
-
-
-contract LibMath is
- SafeMath
-{
- /// @dev Calculates partial value given a numerator and denominator rounded down.
- /// Reverts if rounding error is >= 0.1%
- /// @param numerator Numerator.
- /// @param denominator Denominator.
- /// @param target Value to calculate partial of.
- /// @return Partial value of target rounded down.
- function safeGetPartialAmountFloor(
- uint256 numerator,
- uint256 denominator,
- uint256 target
- )
- internal
- pure
- returns (uint256 partialAmount)
- {
- require(
- denominator > 0,
- "DIVISION_BY_ZERO"
- );
-
- require(
- !isRoundingErrorFloor(
- numerator,
- denominator,
- target
- ),
- "ROUNDING_ERROR"
- );
-
- partialAmount = safeDiv(
- safeMul(numerator, target),
- denominator
- );
- return partialAmount;
- }
-
- /// @dev Calculates partial value given a numerator and denominator rounded down.
- /// Reverts if rounding error is >= 0.1%
- /// @param numerator Numerator.
- /// @param denominator Denominator.
- /// @param target Value to calculate partial of.
- /// @return Partial value of target rounded up.
- function safeGetPartialAmountCeil(
- uint256 numerator,
- uint256 denominator,
- uint256 target
- )
- internal
- pure
- returns (uint256 partialAmount)
- {
- require(
- denominator > 0,
- "DIVISION_BY_ZERO"
- );
-
- require(
- !isRoundingErrorCeil(
- numerator,
- denominator,
- target
- ),
- "ROUNDING_ERROR"
- );
-
- // safeDiv computes `floor(a / b)`. We use the identity (a, b integer):
- // ceil(a / b) = floor((a + b - 1) / b)
- // To implement `ceil(a / b)` using safeDiv.
- partialAmount = safeDiv(
- safeAdd(
- safeMul(numerator, target),
- safeSub(denominator, 1)
- ),
- denominator
- );
- return partialAmount;
- }
-
- /// @dev Calculates partial value given a numerator and denominator rounded down.
- /// @param numerator Numerator.
- /// @param denominator Denominator.
- /// @param target Value to calculate partial of.
- /// @return Partial value of target rounded down.
- function getPartialAmountFloor(
- uint256 numerator,
- uint256 denominator,
- uint256 target
- )
- internal
- pure
- returns (uint256 partialAmount)
- {
- require(
- denominator > 0,
- "DIVISION_BY_ZERO"
- );
-
- partialAmount = safeDiv(
- safeMul(numerator, target),
- denominator
- );
- return partialAmount;
- }
-
- /// @dev Calculates partial value given a numerator and denominator rounded down.
- /// @param numerator Numerator.
- /// @param denominator Denominator.
- /// @param target Value to calculate partial of.
- /// @return Partial value of target rounded up.
- function getPartialAmountCeil(
- uint256 numerator,
- uint256 denominator,
- uint256 target
- )
- internal
- pure
- returns (uint256 partialAmount)
- {
- require(
- denominator > 0,
- "DIVISION_BY_ZERO"
- );
-
- // safeDiv computes `floor(a / b)`. We use the identity (a, b integer):
- // ceil(a / b) = floor((a + b - 1) / b)
- // To implement `ceil(a / b)` using safeDiv.
- partialAmount = safeDiv(
- safeAdd(
- safeMul(numerator, target),
- safeSub(denominator, 1)
- ),
- denominator
- );
- return partialAmount;
- }
-
- /// @dev Checks if rounding error >= 0.1% when rounding down.
- /// @param numerator Numerator.
- /// @param denominator Denominator.
- /// @param target Value to multiply with numerator/denominator.
- /// @return Rounding error is present.
- function isRoundingErrorFloor(
- uint256 numerator,
- uint256 denominator,
- uint256 target
- )
- internal
- pure
- returns (bool isError)
- {
- require(
- denominator > 0,
- "DIVISION_BY_ZERO"
- );
-
- // The absolute rounding error is the difference between the rounded
- // value and the ideal value. The relative rounding error is the
- // absolute rounding error divided by the absolute value of the
- // ideal value. This is undefined when the ideal value is zero.
- //
- // The ideal value is `numerator * target / denominator`.
- // Let's call `numerator * target % denominator` the remainder.
- // The absolute error is `remainder / denominator`.
- //
- // When the ideal value is zero, we require the absolute error to
- // be zero. Fortunately, this is always the case. The ideal value is
- // zero iff `numerator == 0` and/or `target == 0`. In this case the
- // remainder and absolute error are also zero.
- if (target == 0 || numerator == 0) {
- return false;
- }
-
- // Otherwise, we want the relative rounding error to be strictly
- // less than 0.1%.
- // The relative error is `remainder / (numerator * target)`.
- // We want the relative error less than 1 / 1000:
- // remainder / (numerator * denominator) < 1 / 1000
- // or equivalently:
- // 1000 * remainder < numerator * target
- // so we have a rounding error iff:
- // 1000 * remainder >= numerator * target
- uint256 remainder = mulmod(
- target,
- numerator,
- denominator
- );
- isError = safeMul(1000, remainder) >= safeMul(numerator, target);
- return isError;
- }
-
- /// @dev Checks if rounding error >= 0.1% when rounding up.
- /// @param numerator Numerator.
- /// @param denominator Denominator.
- /// @param target Value to multiply with numerator/denominator.
- /// @return Rounding error is present.
- function isRoundingErrorCeil(
- uint256 numerator,
- uint256 denominator,
- uint256 target
- )
- internal
- pure
- returns (bool isError)
- {
- require(
- denominator > 0,
- "DIVISION_BY_ZERO"
- );
-
- // See the comments in `isRoundingError`.
- if (target == 0 || numerator == 0) {
- // When either is zero, the ideal value and rounded value are zero
- // and there is no rounding error. (Although the relative error
- // is undefined.)
- return false;
- }
- // Compute remainder as before
- uint256 remainder = mulmod(
- target,
- numerator,
- denominator
- );
- remainder = safeSub(denominator, remainder) % denominator;
- isError = safeMul(1000, remainder) >= safeMul(numerator, target);
- return isError;
- }
-}
diff --git a/packages/contracts/contracts/protocol/Exchange/libs/LibOrder.sol b/packages/contracts/contracts/protocol/Exchange/libs/LibOrder.sol
deleted file mode 100644
index 0fe7c2161..000000000
--- a/packages/contracts/contracts/protocol/Exchange/libs/LibOrder.sol
+++ /dev/null
@@ -1,145 +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 "./LibEIP712.sol";
-
-
-contract LibOrder is
- LibEIP712
-{
- // Hash for the EIP712 Order Schema
- bytes32 constant internal EIP712_ORDER_SCHEMA_HASH = keccak256(abi.encodePacked(
- "Order(",
- "address makerAddress,",
- "address takerAddress,",
- "address feeRecipientAddress,",
- "address senderAddress,",
- "uint256 makerAssetAmount,",
- "uint256 takerAssetAmount,",
- "uint256 makerFee,",
- "uint256 takerFee,",
- "uint256 expirationTimeSeconds,",
- "uint256 salt,",
- "bytes makerAssetData,",
- "bytes takerAssetData",
- ")"
- ));
-
- // A valid order remains fillable until it is expired, fully filled, or cancelled.
- // An order's state is unaffected by external factors, like account balances.
- enum OrderStatus {
- INVALID, // Default value
- INVALID_MAKER_ASSET_AMOUNT, // Order does not have a valid maker asset amount
- INVALID_TAKER_ASSET_AMOUNT, // Order does not have a valid taker asset amount
- FILLABLE, // Order is fillable
- EXPIRED, // Order has already expired
- FULLY_FILLED, // Order is fully filled
- CANCELLED // Order has been cancelled
- }
-
- // solhint-disable max-line-length
- struct Order {
- address makerAddress; // Address that created the order.
- address takerAddress; // Address that is allowed to fill the order. If set to 0, any address is allowed to fill the order.
- address feeRecipientAddress; // Address that will recieve fees when order is filled.
- address senderAddress; // Address that is allowed to call Exchange contract methods that affect this order. If set to 0, any address is allowed to call these methods.
- uint256 makerAssetAmount; // Amount of makerAsset being offered by maker. Must be greater than 0.
- uint256 takerAssetAmount; // Amount of takerAsset being bid on by maker. Must be greater than 0.
- uint256 makerFee; // Amount of ZRX paid to feeRecipient by maker when order is filled. If set to 0, no transfer of ZRX from maker to feeRecipient will be attempted.
- uint256 takerFee; // Amount of ZRX paid to feeRecipient by taker when order is filled. If set to 0, no transfer of ZRX from taker to feeRecipient will be attempted.
- uint256 expirationTimeSeconds; // Timestamp in seconds at which order expires.
- uint256 salt; // Arbitrary number to facilitate uniqueness of the order's hash.
- bytes makerAssetData; // Encoded data that can be decoded by a specified proxy contract when transferring makerAsset. The last byte references the id of this proxy.
- bytes takerAssetData; // Encoded data that can be decoded by a specified proxy contract when transferring takerAsset. The last byte references the id of this proxy.
- }
- // solhint-enable max-line-length
-
- struct OrderInfo {
- uint8 orderStatus; // Status that describes order's validity and fillability.
- bytes32 orderHash; // EIP712 hash of the order (see LibOrder.getOrderHash).
- uint256 orderTakerAssetFilledAmount; // Amount of order that has already been filled.
- }
-
- /// @dev Calculates Keccak-256 hash of the order.
- /// @param order The order structure.
- /// @return Keccak-256 EIP712 hash of the order.
- function getOrderHash(Order memory order)
- internal
- view
- returns (bytes32 orderHash)
- {
- orderHash = hashEIP712Message(hashOrder(order));
- return orderHash;
- }
-
- /// @dev Calculates EIP712 hash of the order.
- /// @param order The order structure.
- /// @return EIP712 hash of the order.
- function hashOrder(Order memory order)
- internal
- pure
- returns (bytes32 result)
- {
- bytes32 schemaHash = EIP712_ORDER_SCHEMA_HASH;
- bytes32 makerAssetDataHash = keccak256(order.makerAssetData);
- bytes32 takerAssetDataHash = keccak256(order.takerAssetData);
-
- // Assembly for more efficiently computing:
- // keccak256(abi.encodePacked(
- // EIP712_ORDER_SCHEMA_HASH,
- // bytes32(order.makerAddress),
- // bytes32(order.takerAddress),
- // bytes32(order.feeRecipientAddress),
- // bytes32(order.senderAddress),
- // order.makerAssetAmount,
- // order.takerAssetAmount,
- // order.makerFee,
- // order.takerFee,
- // order.expirationTimeSeconds,
- // order.salt,
- // keccak256(order.makerAssetData),
- // keccak256(order.takerAssetData)
- // ));
-
- assembly {
- // Calculate memory addresses that will be swapped out before hashing
- let pos1 := sub(order, 32)
- let pos2 := add(order, 320)
- let pos3 := add(order, 352)
-
- // Backup
- let temp1 := mload(pos1)
- let temp2 := mload(pos2)
- let temp3 := mload(pos3)
-
- // Hash in place
- mstore(pos1, schemaHash)
- mstore(pos2, makerAssetDataHash)
- mstore(pos3, takerAssetDataHash)
- result := keccak256(pos1, 416)
-
- // Restore
- mstore(pos1, temp1)
- mstore(pos2, temp2)
- mstore(pos3, temp3)
- }
- return result;
- }
-}
diff --git a/packages/contracts/contracts/protocol/Exchange/mixins/MAssetProxyDispatcher.sol b/packages/contracts/contracts/protocol/Exchange/mixins/MAssetProxyDispatcher.sol
deleted file mode 100644
index 0ddfca270..000000000
--- a/packages/contracts/contracts/protocol/Exchange/mixins/MAssetProxyDispatcher.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 "../interfaces/IAssetProxyDispatcher.sol";
-
-
-contract MAssetProxyDispatcher is
- IAssetProxyDispatcher
-{
- // Logs registration of new asset proxy
- event AssetProxyRegistered(
- bytes4 id, // Id of new registered AssetProxy.
- address assetProxy // Address of new registered AssetProxy.
- );
-
- /// @dev Forwards arguments to assetProxy and calls `transferFrom`. Either succeeds or throws.
- /// @param assetData Byte array encoded for the asset.
- /// @param from Address to transfer token from.
- /// @param to Address to transfer token to.
- /// @param amount Amount of token to transfer.
- function dispatchTransferFrom(
- bytes memory assetData,
- address from,
- address to,
- uint256 amount
- )
- internal;
-}
diff --git a/packages/contracts/contracts/protocol/Exchange/mixins/MExchangeCore.sol b/packages/contracts/contracts/protocol/Exchange/mixins/MExchangeCore.sol
deleted file mode 100644
index 742499568..000000000
--- a/packages/contracts/contracts/protocol/Exchange/mixins/MExchangeCore.sol
+++ /dev/null
@@ -1,157 +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/LibOrder.sol";
-import "../libs/LibFillResults.sol";
-import "../interfaces/IExchangeCore.sol";
-
-
-contract MExchangeCore is
- IExchangeCore
-{
- // Fill event is emitted whenever an order is filled.
- event Fill(
- address indexed makerAddress, // Address that created the order.
- address indexed feeRecipientAddress, // Address that received fees.
- address takerAddress, // Address that filled the order.
- address senderAddress, // Address that called the Exchange contract (msg.sender).
- uint256 makerAssetFilledAmount, // Amount of makerAsset sold by maker and bought by taker.
- uint256 takerAssetFilledAmount, // Amount of takerAsset sold by taker and bought by maker.
- uint256 makerFeePaid, // Amount of ZRX paid to feeRecipient by maker.
- uint256 takerFeePaid, // Amount of ZRX paid to feeRecipient by taker.
- bytes32 indexed orderHash, // EIP712 hash of order (see LibOrder.getOrderHash).
- bytes makerAssetData, // Encoded data specific to makerAsset.
- bytes takerAssetData // Encoded data specific to takerAsset.
- );
-
- // Cancel event is emitted whenever an individual order is cancelled.
- event Cancel(
- address indexed makerAddress, // Address that created the order.
- address indexed feeRecipientAddress, // Address that would have recieved fees if order was filled.
- address senderAddress, // Address that called the Exchange contract (msg.sender).
- bytes32 indexed orderHash, // EIP712 hash of order (see LibOrder.getOrderHash).
- bytes makerAssetData, // Encoded data specific to makerAsset.
- bytes takerAssetData // Encoded data specific to takerAsset.
- );
-
- // CancelUpTo event is emitted whenever `cancelOrdersUpTo` is executed succesfully.
- event CancelUpTo(
- address indexed makerAddress, // Orders cancelled must have been created by this address.
- address indexed senderAddress, // Orders cancelled must have a `senderAddress` equal to this address.
- uint256 orderEpoch // Orders with specified makerAddress and senderAddress with a salt less than this value are considered cancelled.
- );
-
- /// @dev Fills the input order.
- /// @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 fillOrderInternal(
- LibOrder.Order memory order,
- uint256 takerAssetFillAmount,
- bytes memory signature
- )
- internal
- returns (LibFillResults.FillResults memory fillResults);
-
- /// @dev After calling, the order can not be filled anymore.
- /// @param order Order struct containing order specifications.
- function cancelOrderInternal(LibOrder.Order memory order)
- internal;
-
- /// @dev Updates state with results of a fill order.
- /// @param order that was filled.
- /// @param takerAddress Address of taker who filled the order.
- /// @param orderTakerAssetFilledAmount Amount of order already filled.
- /// @return fillResults Amounts filled and fees paid by maker and taker.
- function updateFilledState(
- LibOrder.Order memory order,
- address takerAddress,
- bytes32 orderHash,
- uint256 orderTakerAssetFilledAmount,
- LibFillResults.FillResults memory fillResults
- )
- internal;
-
- /// @dev Updates state with results of cancelling an order.
- /// State is only updated if the order is currently fillable.
- /// Otherwise, updating state would have no effect.
- /// @param order that was cancelled.
- /// @param orderHash Hash of order that was cancelled.
- function updateCancelledState(
- LibOrder.Order memory order,
- bytes32 orderHash
- )
- internal;
-
- /// @dev Validates context for fillOrder. Succeeds or throws.
- /// @param order to be filled.
- /// @param orderInfo OrderStatus, orderHash, and amount already filled of order.
- /// @param takerAddress Address of order taker.
- /// @param signature Proof that the orders was created by its maker.
- function assertFillableOrder(
- LibOrder.Order memory order,
- LibOrder.OrderInfo memory orderInfo,
- address takerAddress,
- bytes memory signature
- )
- internal
- view;
-
- /// @dev Validates context for fillOrder. Succeeds or throws.
- /// @param order to be filled.
- /// @param orderInfo Status, orderHash, and amount already filled of order.
- /// @param takerAssetFillAmount Desired amount of order to fill by taker.
- /// @param takerAssetFilledAmount Amount of takerAsset that will be filled.
- /// @param makerAssetFilledAmount Amount of makerAsset that will be transfered.
- function assertValidFill(
- LibOrder.Order memory order,
- LibOrder.OrderInfo memory orderInfo,
- uint256 takerAssetFillAmount,
- uint256 takerAssetFilledAmount,
- uint256 makerAssetFilledAmount
- )
- internal
- view;
-
- /// @dev Validates context for cancelOrder. Succeeds or throws.
- /// @param order to be cancelled.
- /// @param orderInfo OrderStatus, orderHash, and amount already filled of order.
- function assertValidCancel(
- LibOrder.Order memory order,
- LibOrder.OrderInfo memory orderInfo
- )
- internal
- view;
-
- /// @dev Calculates amounts filled and fees paid by maker and taker.
- /// @param order to be filled.
- /// @param takerAssetFilledAmount Amount of takerAsset that will be filled.
- /// @return fillResults Amounts filled and fees paid by maker and taker.
- function calculateFillResults(
- LibOrder.Order memory order,
- uint256 takerAssetFilledAmount
- )
- internal
- pure
- returns (LibFillResults.FillResults memory fillResults);
-
-}
diff --git a/packages/contracts/contracts/protocol/Exchange/mixins/MMatchOrders.sol b/packages/contracts/contracts/protocol/Exchange/mixins/MMatchOrders.sol
deleted file mode 100644
index 96fa34bc0..000000000
--- a/packages/contracts/contracts/protocol/Exchange/mixins/MMatchOrders.sol
+++ /dev/null
@@ -1,58 +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/LibOrder.sol";
-import "../libs/LibFillResults.sol";
-import "../interfaces/IMatchOrders.sol";
-
-
-contract MMatchOrders is
- IMatchOrders
-{
- /// @dev Validates context for matchOrders. Succeeds or throws.
- /// @param leftOrder First order to match.
- /// @param rightOrder Second order to match.
- function assertValidMatch(
- LibOrder.Order memory leftOrder,
- LibOrder.Order memory rightOrder
- )
- internal
- pure;
-
- /// @dev Calculates fill amounts for the matched orders.
- /// 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 leftOrder order goes to the taker (who matched the two orders).
- /// @param leftOrder First order to match.
- /// @param rightOrder Second order to match.
- /// @param leftOrderTakerAssetFilledAmount Amount of left order already filled.
- /// @param rightOrderTakerAssetFilledAmount Amount of right order already filled.
- /// @param matchedFillResults Amounts to fill and fees to pay by maker and taker of matched orders.
- function calculateMatchedFillResults(
- LibOrder.Order memory leftOrder,
- LibOrder.Order memory rightOrder,
- uint256 leftOrderTakerAssetFilledAmount,
- uint256 rightOrderTakerAssetFilledAmount
- )
- internal
- pure
- returns (LibFillResults.MatchedFillResults memory matchedFillResults);
-
-}
diff --git a/packages/contracts/contracts/protocol/Exchange/mixins/MSignatureValidator.sol b/packages/contracts/contracts/protocol/Exchange/mixins/MSignatureValidator.sol
deleted file mode 100644
index 1fe88b908..000000000
--- a/packages/contracts/contracts/protocol/Exchange/mixins/MSignatureValidator.sol
+++ /dev/null
@@ -1,75 +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/ISignatureValidator.sol";
-
-
-contract MSignatureValidator is
- ISignatureValidator
-{
- event SignatureValidatorApproval(
- address indexed signerAddress, // Address that approves or disapproves a contract to verify signatures.
- address indexed validatorAddress, // Address of signature validator contract.
- bool approved // Approval or disapproval of validator contract.
- );
-
- // Allowed signature types.
- enum SignatureType {
- Illegal, // 0x00, default value
- Invalid, // 0x01
- EIP712, // 0x02
- EthSign, // 0x03
- Wallet, // 0x04
- Validator, // 0x05
- PreSigned, // 0x06
- NSignatureTypes // 0x07, number of signature types. Always leave at end.
- }
-
- /// @dev Verifies signature using logic defined by Wallet contract.
- /// @param hash Any 32 byte hash.
- /// @param walletAddress Address that should have signed the given hash
- /// and defines its own signature verification method.
- /// @param signature Proof that the hash has been signed by signer.
- /// @return True if the address recovered from the provided signature matches the input signer address.
- function isValidWalletSignature(
- bytes32 hash,
- address walletAddress,
- bytes signature
- )
- internal
- view
- returns (bool isValid);
-
- /// @dev Verifies signature using logic defined by Validator contract.
- /// @param validatorAddress Address of validator contract.
- /// @param hash Any 32 byte hash.
- /// @param signerAddress Address that should have signed the given hash.
- /// @param signature Proof that the hash has been signed by signer.
- /// @return True if the address recovered from the provided signature matches the input signer address.
- function isValidValidatorSignature(
- address validatorAddress,
- bytes32 hash,
- address signerAddress,
- bytes signature
- )
- internal
- view
- returns (bool isValid);
-}
diff --git a/packages/contracts/contracts/protocol/Exchange/mixins/MTransactions.sol b/packages/contracts/contracts/protocol/Exchange/mixins/MTransactions.sol
deleted file mode 100644
index 4f61a4945..000000000
--- a/packages/contracts/contracts/protocol/Exchange/mixins/MTransactions.sol
+++ /dev/null
@@ -1,58 +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/ITransactions.sol";
-
-
-contract MTransactions is
- ITransactions
-{
- // Hash for the EIP712 ZeroEx Transaction Schema
- bytes32 constant internal EIP712_ZEROEX_TRANSACTION_SCHEMA_HASH = keccak256(abi.encodePacked(
- "ZeroExTransaction(",
- "uint256 salt,",
- "address signerAddress,",
- "bytes data",
- ")"
- ));
-
- /// @dev Calculates EIP712 hash of the Transaction.
- /// @param salt Arbitrary number to ensure uniqueness of transaction hash.
- /// @param signerAddress Address of transaction signer.
- /// @param data AbiV2 encoded calldata.
- /// @return EIP712 hash of the Transaction.
- function hashZeroExTransaction(
- uint256 salt,
- address signerAddress,
- bytes memory data
- )
- internal
- pure
- returns (bytes32 result);
-
- /// @dev The current function will be called in the context of this address (either 0x transaction signer or `msg.sender`).
- /// If calling a fill function, this address will represent the taker.
- /// If calling a cancel function, this address will represent the maker.
- /// @return Signer of 0x transaction if entry point is `executeTransaction`.
- /// `msg.sender` if entry point is any other function.
- function getCurrentContextAddress()
- internal
- view
- returns (address);
-}
diff --git a/packages/contracts/contracts/protocol/Exchange/mixins/MWrapperFunctions.sol b/packages/contracts/contracts/protocol/Exchange/mixins/MWrapperFunctions.sol
deleted file mode 100644
index 4adfbde01..000000000
--- a/packages/contracts/contracts/protocol/Exchange/mixins/MWrapperFunctions.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;
-pragma experimental ABIEncoderV2;
-
-import "../libs/LibOrder.sol";
-import "../libs/LibFillResults.sol";
-import "../interfaces/IWrapperFunctions.sol";
-
-
-contract MWrapperFunctions is
- IWrapperFunctions
-{
- /// @dev Fills the input order. Reverts if exact takerAssetFillAmount not filled.
- /// @param order LibOrder.Order struct containing order specifications.
- /// @param takerAssetFillAmount Desired amount of takerAsset to sell.
- /// @param signature Proof that order has been created by maker.
- function fillOrKillOrderInternal(
- LibOrder.Order memory order,
- uint256 takerAssetFillAmount,
- bytes memory signature
- )
- internal
- returns (LibFillResults.FillResults memory fillResults);
-}
diff --git a/packages/contracts/contracts/test/DummyERC20Token/DummyERC20Token.sol b/packages/contracts/contracts/test/DummyERC20Token/DummyERC20Token.sol
deleted file mode 100644
index 412c5d1ad..000000000
--- a/packages/contracts/contracts/test/DummyERC20Token/DummyERC20Token.sol
+++ /dev/null
@@ -1,77 +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 "../../utils/Ownable/Ownable.sol";
-import "../../tokens/ERC20Token/MintableERC20Token.sol";
-
-
-contract DummyERC20Token is
- Ownable,
- MintableERC20Token
-{
- string public name;
- string public symbol;
- uint256 public decimals;
- uint256 public constant MAX_MINT_AMOUNT = 10000000000000000000000;
-
- constructor (
- string _name,
- string _symbol,
- uint256 _decimals,
- uint256 _totalSupply
- )
- public
- {
- name = _name;
- symbol = _symbol;
- decimals = _decimals;
- _totalSupply = _totalSupply;
- balances[msg.sender] = _totalSupply;
- }
-
- /// @dev Sets the balance of target address
- /// @param _target Address or which balance will be updated
- /// @param _value New balance of target address
- function setBalance(address _target, uint256 _value)
- external
- onlyOwner
- {
- uint256 currBalance = balances[_target];
- if (_value < currBalance) {
- _totalSupply = safeSub(_totalSupply, safeSub(currBalance, _value));
- } else {
- _totalSupply = safeAdd(_totalSupply, safeSub(_value, currBalance));
- }
- balances[_target] = _value;
- }
-
- /// @dev Mints new tokens for sender
- /// @param _value Amount of tokens to mint
- function mint(uint256 _value)
- external
- {
- require(
- _value <= MAX_MINT_AMOUNT,
- "VALUE_TOO_LARGE"
- );
-
- _mint(msg.sender, _value);
- }
-}
diff --git a/packages/contracts/contracts/test/DummyERC20Token/DummyMultipleReturnERC20Token.sol b/packages/contracts/contracts/test/DummyERC20Token/DummyMultipleReturnERC20Token.sol
deleted file mode 100644
index 733d4437e..000000000
--- a/packages/contracts/contracts/test/DummyERC20Token/DummyMultipleReturnERC20Token.sol
+++ /dev/null
@@ -1,69 +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 "./DummyERC20Token.sol";
-
-
-// solhint-disable no-empty-blocks
-contract DummyMultipleReturnERC20Token is
- DummyERC20Token
-{
- constructor (
- string _name,
- string _symbol,
- uint256 _decimals,
- uint256 _totalSupply
- )
- public
- DummyERC20Token(
- _name,
- _symbol,
- _decimals,
- _totalSupply
- )
- {}
-
- /// @dev send `value` token to `to` from `from` on the condition it is approved by `from`
- /// @param _from The address of the sender
- /// @param _to The address of the recipient
- /// @param _value The amount of token to be transferred
- function transferFrom(
- address _from,
- address _to,
- uint256 _value
- )
- external
- returns (bool)
- {
- emit Transfer(
- _from,
- _to,
- _value
- );
-
- // HACK: This contract will not compile if we remove `returns (bool)`, so we manually return 64 bytes (equiavalent to true, true)
- assembly {
- mstore(0, 1)
- mstore(32, 1)
- return(0, 64)
- }
- }
-}
-
diff --git a/packages/contracts/contracts/test/DummyERC20Token/DummyNoReturnERC20Token.sol b/packages/contracts/contracts/test/DummyERC20Token/DummyNoReturnERC20Token.sol
deleted file mode 100644
index e16825a16..000000000
--- a/packages/contracts/contracts/test/DummyERC20Token/DummyNoReturnERC20Token.sol
+++ /dev/null
@@ -1,115 +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 "./DummyERC20Token.sol";
-
-
-// solhint-disable no-empty-blocks
-contract DummyNoReturnERC20Token is
- DummyERC20Token
-{
- constructor (
- string _name,
- string _symbol,
- uint256 _decimals,
- uint256 _totalSupply
- )
- public
- DummyERC20Token(
- _name,
- _symbol,
- _decimals,
- _totalSupply
- )
- {}
-
- /// @dev send `value` token to `to` from `msg.sender`
- /// @param _to The address of the recipient
- /// @param _value The amount of token to be transferred
- function transfer(address _to, uint256 _value)
- external
- returns (bool)
- {
- require(
- balances[msg.sender] >= _value,
- "ERC20_INSUFFICIENT_BALANCE"
- );
- require(
- balances[_to] + _value >= balances[_to],
- "UINT256_OVERFLOW"
- );
-
- balances[msg.sender] -= _value;
- balances[_to] += _value;
-
- emit Transfer(
- msg.sender,
- _to,
- _value
- );
-
- // HACK: This contract will not compile if we remove `returns (bool)`, so we manually return no data
- assembly {
- return(0, 0)
- }
- }
-
- /// @dev send `value` token to `to` from `from` on the condition it is approved by `from`
- /// @param _from The address of the sender
- /// @param _to The address of the recipient
- /// @param _value The amount of token to be transferred
- function transferFrom(
- address _from,
- address _to,
- uint256 _value
- )
- external
- returns (bool)
- {
- require(
- balances[_from] >= _value,
- "ERC20_INSUFFICIENT_BALANCE"
- );
- require(
- allowed[_from][msg.sender] >= _value,
- "ERC20_INSUFFICIENT_ALLOWANCE"
- );
- require(
- balances[_to] + _value >= balances[_to],
- "UINT256_OVERFLOW"
- );
-
- balances[_to] += _value;
- balances[_from] -= _value;
- allowed[_from][msg.sender] -= _value;
-
- emit Transfer(
- _from,
- _to,
- _value
- );
-
- // HACK: This contract will not compile if we remove `returns (bool)`, so we manually return no data
- assembly {
- return(0, 0)
- }
- }
-}
-
diff --git a/packages/contracts/contracts/test/DummyERC721Receiver/DummyERC721Receiver.sol b/packages/contracts/contracts/test/DummyERC721Receiver/DummyERC721Receiver.sol
deleted file mode 100644
index 6c8371559..000000000
--- a/packages/contracts/contracts/test/DummyERC721Receiver/DummyERC721Receiver.sol
+++ /dev/null
@@ -1,67 +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 "../../tokens/ERC721Token/IERC721Receiver.sol";
-
-
-contract DummyERC721Receiver is
- IERC721Receiver
-{
- // Function selector for ERC721Receiver.onERC721Received
- // 0x150b7a02
- bytes4 constant internal ERC721_RECEIVED = bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"));
-
- event TokenReceived(
- address operator,
- address from,
- uint256 tokenId,
- bytes data
- );
-
- /// @notice Handle the receipt of an NFT
- /// @dev The ERC721 smart contract calls this function on the recipient
- /// after a `transfer`. This function MAY throw to revert and reject the
- /// transfer. Return of other than the magic value MUST result in the
- /// transaction being reverted.
- /// Note: the contract address is always the message sender.
- /// @param _operator The address which called `safeTransferFrom` function
- /// @param _from The address which previously owned the token
- /// @param _tokenId The NFT identifier which is being transferred
- /// @param _data Additional data with no specified format
- /// @return `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
- /// unless throwing
- function onERC721Received(
- address _operator,
- address _from,
- uint256 _tokenId,
- bytes _data
- )
- external
- returns (bytes4)
- {
- emit TokenReceived(
- _operator,
- _from,
- _tokenId,
- _data
- );
- return ERC721_RECEIVED;
- }
-}
diff --git a/packages/contracts/contracts/test/DummyERC721Receiver/InvalidERC721Receiver.sol b/packages/contracts/contracts/test/DummyERC721Receiver/InvalidERC721Receiver.sol
deleted file mode 100644
index 309633bf5..000000000
--- a/packages/contracts/contracts/test/DummyERC721Receiver/InvalidERC721Receiver.sol
+++ /dev/null
@@ -1,66 +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 "../../tokens/ERC721Token/IERC721Receiver.sol";
-
-
-contract InvalidERC721Receiver is
- IERC721Receiver
-{
- // Actual function signature is `onERC721Received(address,address,uint256,bytes)`
- bytes4 constant internal INVALID_ERC721_RECEIVED = bytes4(keccak256("onERC721Received(address,uint256,bytes)"));
-
- event TokenReceived(
- address operator,
- address from,
- uint256 tokenId,
- bytes data
- );
-
- /// @notice Handle the receipt of an NFT
- /// @dev The ERC721 smart contract calls this function on the recipient
- /// after a `transfer`. This function MAY throw to revert and reject the
- /// transfer. Return of other than the magic value MUST result in the
- /// transaction being reverted.
- /// Note: the contract address is always the message sender.
- /// @param _operator The address which called `safeTransferFrom` function
- /// @param _from The address which previously owned the token
- /// @param _tokenId The NFT identifier which is being transferred
- /// @param _data Additional data with no specified format
- /// @return `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
- /// unless throwing
- function onERC721Received(
- address _operator,
- address _from,
- uint256 _tokenId,
- bytes _data
- )
- external
- returns (bytes4)
- {
- emit TokenReceived(
- _operator,
- _from,
- _tokenId,
- _data
- );
- return INVALID_ERC721_RECEIVED;
- }
-}
diff --git a/packages/contracts/contracts/test/DummyERC721Token/DummyERC721Token.sol b/packages/contracts/contracts/test/DummyERC721Token/DummyERC721Token.sol
deleted file mode 100644
index ac9068d1d..000000000
--- a/packages/contracts/contracts/test/DummyERC721Token/DummyERC721Token.sol
+++ /dev/null
@@ -1,63 +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 "../../tokens/ERC721Token/MintableERC721Token.sol";
-import "../../utils/Ownable/Ownable.sol";
-
-
-// solhint-disable no-empty-blocks
-contract DummyERC721Token is
- Ownable,
- MintableERC721Token
-{
- string public name;
- string public symbol;
-
- constructor (
- string _name,
- string _symbol
- )
- public
- {
- name = _name;
- symbol = _symbol;
- }
-
- /// @dev Function to mint a new token
- /// Reverts if the given token ID already exists
- /// @param _to Address of the beneficiary that will own the minted token
- /// @param _tokenId ID of the token to be minted by the msg.sender
- function mint(address _to, uint256 _tokenId)
- external
- {
- _mint(_to, _tokenId);
- }
-
- /// @dev Function to burn a token
- /// Reverts if the given token ID doesn't exist or not called by contract owner
- /// @param _owner Owner of token with given token ID
- /// @param _tokenId ID of the token to be burned by the msg.sender
- function burn(address _owner, uint256 _tokenId)
- external
- onlyOwner
- {
- _burn(_owner, _tokenId);
- }
-}
diff --git a/packages/contracts/contracts/test/ReentrantERC20Token/ReentrantERC20Token.sol b/packages/contracts/contracts/test/ReentrantERC20Token/ReentrantERC20Token.sol
deleted file mode 100644
index 99dd47a78..000000000
--- a/packages/contracts/contracts/test/ReentrantERC20Token/ReentrantERC20Token.sol
+++ /dev/null
@@ -1,188 +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 "../../utils/LibBytes/LibBytes.sol";
-import "../../tokens/ERC20Token/ERC20Token.sol";
-import "../../protocol/Exchange/interfaces/IExchange.sol";
-import "../../protocol/Exchange/libs/LibOrder.sol";
-
-
-// solhint-disable no-unused-vars
-contract ReentrantERC20Token is
- ERC20Token
-{
- using LibBytes for bytes;
-
- // solhint-disable-next-line var-name-mixedcase
- IExchange internal EXCHANGE;
-
- bytes internal constant REENTRANCY_ILLEGAL_REVERT_REASON = abi.encodeWithSelector(
- bytes4(keccak256("Error(string)")),
- "REENTRANCY_ILLEGAL"
- );
-
- // All of these functions are potentially vulnerable to reentrancy
- // We do not test any "noThrow" functions because `fillOrderNoThrow` makes a delegatecall to `fillOrder`
- enum ExchangeFunction {
- FILL_ORDER,
- FILL_OR_KILL_ORDER,
- BATCH_FILL_ORDERS,
- BATCH_FILL_OR_KILL_ORDERS,
- MARKET_BUY_ORDERS,
- MARKET_SELL_ORDERS,
- MATCH_ORDERS,
- CANCEL_ORDER,
- BATCH_CANCEL_ORDERS,
- CANCEL_ORDERS_UP_TO,
- SET_SIGNATURE_VALIDATOR_APPROVAL
- }
-
- uint8 internal currentFunctionId = 0;
-
- constructor (address _exchange)
- public
- {
- EXCHANGE = IExchange(_exchange);
- }
-
- /// @dev Set the current function that will be called when `transferFrom` is called.
- /// @param _currentFunctionId Id that corresponds to function name.
- function setCurrentFunction(uint8 _currentFunctionId)
- external
- {
- currentFunctionId = _currentFunctionId;
- }
-
- /// @dev A version of `transferFrom` that attempts to reenter the Exchange contract.
- /// @param _from The address of the sender
- /// @param _to The address of the recipient
- /// @param _value The amount of token to be transferred
- function transferFrom(
- address _from,
- address _to,
- uint256 _value
- )
- external
- returns (bool)
- {
- // This order would normally be invalid, but it will be used strictly for testing reentrnacy.
- // Any reentrancy checks will happen before any other checks that invalidate the order.
- LibOrder.Order memory order;
-
- // Initialize remaining null parameters
- bytes memory signature;
- LibOrder.Order[] memory orders;
- uint256[] memory takerAssetFillAmounts;
- bytes[] memory signatures;
- bytes memory calldata;
-
- // Create calldata for function that corresponds to currentFunctionId
- if (currentFunctionId == uint8(ExchangeFunction.FILL_ORDER)) {
- calldata = abi.encodeWithSelector(
- EXCHANGE.fillOrder.selector,
- order,
- 0,
- signature
- );
- } else if (currentFunctionId == uint8(ExchangeFunction.FILL_OR_KILL_ORDER)) {
- calldata = abi.encodeWithSelector(
- EXCHANGE.fillOrKillOrder.selector,
- order,
- 0,
- signature
- );
- } else if (currentFunctionId == uint8(ExchangeFunction.BATCH_FILL_ORDERS)) {
- calldata = abi.encodeWithSelector(
- EXCHANGE.batchFillOrders.selector,
- orders,
- takerAssetFillAmounts,
- signatures
- );
- } else if (currentFunctionId == uint8(ExchangeFunction.BATCH_FILL_OR_KILL_ORDERS)) {
- calldata = abi.encodeWithSelector(
- EXCHANGE.batchFillOrKillOrders.selector,
- orders,
- takerAssetFillAmounts,
- signatures
- );
- } else if (currentFunctionId == uint8(ExchangeFunction.MARKET_BUY_ORDERS)) {
- calldata = abi.encodeWithSelector(
- EXCHANGE.marketBuyOrders.selector,
- orders,
- 0,
- signatures
- );
- } else if (currentFunctionId == uint8(ExchangeFunction.MARKET_SELL_ORDERS)) {
- calldata = abi.encodeWithSelector(
- EXCHANGE.marketSellOrders.selector,
- orders,
- 0,
- signatures
- );
- } else if (currentFunctionId == uint8(ExchangeFunction.MATCH_ORDERS)) {
- calldata = abi.encodeWithSelector(
- EXCHANGE.matchOrders.selector,
- order,
- order,
- signature,
- signature
- );
- } else if (currentFunctionId == uint8(ExchangeFunction.CANCEL_ORDER)) {
- calldata = abi.encodeWithSelector(
- EXCHANGE.cancelOrder.selector,
- order
- );
- } else if (currentFunctionId == uint8(ExchangeFunction.BATCH_CANCEL_ORDERS)) {
- calldata = abi.encodeWithSelector(
- EXCHANGE.batchCancelOrders.selector,
- orders
- );
- } else if (currentFunctionId == uint8(ExchangeFunction.CANCEL_ORDERS_UP_TO)) {
- calldata = abi.encodeWithSelector(
- EXCHANGE.cancelOrdersUpTo.selector,
- 0
- );
- } else if (currentFunctionId == uint8(ExchangeFunction.SET_SIGNATURE_VALIDATOR_APPROVAL)) {
- calldata = abi.encodeWithSelector(
- EXCHANGE.setSignatureValidatorApproval.selector,
- address(0),
- false
- );
- }
-
- // Call Exchange function, swallow error
- address(EXCHANGE).call(calldata);
-
- // Revert reason is 100 bytes
- bytes memory returnData = new bytes(100);
-
- // Copy return data
- assembly {
- returndatacopy(add(returnData, 32), 0, 100)
- }
-
- // Revert if function reverted with REENTRANCY_ILLEGAL error
- require(!REENTRANCY_ILLEGAL_REVERT_REASON.equals(returnData));
-
- // Transfer will return true if function failed for any other reason
- return true;
- }
-} \ No newline at end of file
diff --git a/packages/contracts/contracts/test/TestAssetProxyDispatcher/TestAssetProxyDispatcher.sol b/packages/contracts/contracts/test/TestAssetProxyDispatcher/TestAssetProxyDispatcher.sol
deleted file mode 100644
index ad71fc9a1..000000000
--- a/packages/contracts/contracts/test/TestAssetProxyDispatcher/TestAssetProxyDispatcher.sol
+++ /dev/null
@@ -1,37 +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 "../../protocol/Exchange/MixinAssetProxyDispatcher.sol";
-
-
-contract TestAssetProxyDispatcher is
- MixinAssetProxyDispatcher
-{
- function publicDispatchTransferFrom(
- bytes memory assetData,
- address from,
- address to,
- uint256 amount
- )
- public
- {
- dispatchTransferFrom(assetData, from, to, amount);
- }
-}
diff --git a/packages/contracts/contracts/test/TestAssetProxyOwner/TestAssetProxyOwner.sol b/packages/contracts/contracts/test/TestAssetProxyOwner/TestAssetProxyOwner.sol
deleted file mode 100644
index 52c66cb56..000000000
--- a/packages/contracts/contracts/test/TestAssetProxyOwner/TestAssetProxyOwner.sol
+++ /dev/null
@@ -1,58 +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 "../../protocol/AssetProxyOwner/AssetProxyOwner.sol";
-
-
-// solhint-disable no-empty-blocks
-contract TestAssetProxyOwner is
- AssetProxyOwner
-{
- constructor (
- address[] memory _owners,
- address[] memory _assetProxyContracts,
- uint256 _required,
- uint256 _secondsTimeLocked
- )
- public
- AssetProxyOwner(_owners, _assetProxyContracts, _required, _secondsTimeLocked)
- {}
-
- function testValidRemoveAuthorizedAddressAtIndexTx(uint256 id)
- public
- view
- validRemoveAuthorizedAddressAtIndexTx(id)
- returns (bool)
- {
- // Do nothing. We expect reverts through the modifier
- return true;
- }
-
- /// @dev Compares first 4 bytes of byte array to `removeAuthorizedAddressAtIndex` function selector.
- /// @param data Transaction data.
- /// @return Successful if data is a call to `removeAuthorizedAddressAtIndex`.
- function isFunctionRemoveAuthorizedAddressAtIndex(bytes memory data)
- public
- pure
- returns (bool)
- {
- return data.readBytes4(0) == REMOVE_AUTHORIZED_ADDRESS_AT_INDEX_SELECTOR;
- }
-}
diff --git a/packages/contracts/contracts/test/TestConstants/TestConstants.sol b/packages/contracts/contracts/test/TestConstants/TestConstants.sol
deleted file mode 100644
index 1275d007b..000000000
--- a/packages/contracts/contracts/test/TestConstants/TestConstants.sol
+++ /dev/null
@@ -1,57 +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 "../../utils/LibBytes/LibBytes.sol";
-
-
-// solhint-disable max-line-length
-contract TestConstants {
-
- using LibBytes for bytes;
-
- bytes4 constant internal ERC20_PROXY_ID = bytes4(keccak256("ERC20Token(address)"));
-
- address constant internal KOVAN_ZRX_ADDRESS = 0x6Ff6C0Ff1d68b964901F986d4C9FA3ac68346570;
- bytes constant internal KOVAN_ZRX_ASSET_DATA = "\xf4\x72\x61\xb0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x6f\xf6\xc0\xff\x1d\x68\xb9\x64\x90\x1f\x98\x6d\x4c\x9f\xa3\xac\x68\x34\x65\x70";
-
- address constant internal MAINNET_ZRX_ADDRESS = 0xE41d2489571d322189246DaFA5ebDe1F4699F498;
- bytes constant public MAINNET_ZRX_ASSET_DATA = "\xf4\x72\x61\xb0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe4\x1d\x24\x89\x57\x1d\x32\x21\x89\x24\x6d\xaf\xa5\xeb\xde\x1f\x46\x99\xf4\x98";
-
- function assertValidZrxAssetData()
- public
- pure
- returns (bool)
- {
- bytes memory kovanZrxAssetData = abi.encodeWithSelector(ERC20_PROXY_ID, KOVAN_ZRX_ADDRESS);
- require(
- kovanZrxAssetData.equals(KOVAN_ZRX_ASSET_DATA),
- "INVALID_KOVAN_ZRX_ASSET_DATA"
- );
-
- bytes memory mainetZrxAssetData = abi.encodeWithSelector(ERC20_PROXY_ID, MAINNET_ZRX_ADDRESS);
- require(
- mainetZrxAssetData.equals(MAINNET_ZRX_ASSET_DATA),
- "INVALID_MAINNET_ZRX_ASSET_DATA"
- );
-
- return true;
- }
-}
-// solhint-enable max-line-length \ No newline at end of file
diff --git a/packages/contracts/contracts/test/TestExchangeInternals/TestExchangeInternals.sol b/packages/contracts/contracts/test/TestExchangeInternals/TestExchangeInternals.sol
deleted file mode 100644
index 27187f8f8..000000000
--- a/packages/contracts/contracts/test/TestExchangeInternals/TestExchangeInternals.sol
+++ /dev/null
@@ -1,191 +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 "../../protocol/Exchange/Exchange.sol";
-
-
-// solhint-disable no-empty-blocks
-contract TestExchangeInternals is
- Exchange
-{
- constructor ()
- public
- Exchange("")
- {}
-
- /// @dev Adds properties of both FillResults instances.
- /// Modifies the first FillResults instance specified.
- /// Note that this function has been modified from the original
- // internal version to return the FillResults.
- /// @param totalFillResults Fill results instance that will be added onto.
- /// @param singleFillResults Fill results instance that will be added to totalFillResults.
- /// @return newTotalFillResults The result of adding singleFillResults to totalFilResults.
- function publicAddFillResults(FillResults memory totalFillResults, FillResults memory singleFillResults)
- public
- pure
- returns (FillResults memory)
- {
- addFillResults(totalFillResults, singleFillResults);
- return totalFillResults;
- }
-
- /// @dev Calculates amounts filled and fees paid by maker and taker.
- /// @param order to be filled.
- /// @param takerAssetFilledAmount Amount of takerAsset that will be filled.
- /// @return fillResults Amounts filled and fees paid by maker and taker.
- function publicCalculateFillResults(
- Order memory order,
- uint256 takerAssetFilledAmount
- )
- public
- pure
- returns (FillResults memory fillResults)
- {
- return calculateFillResults(order, takerAssetFilledAmount);
- }
-
- /// @dev Calculates partial value given a numerator and denominator.
- /// Reverts if rounding error is >= 0.1%
- /// @param numerator Numerator.
- /// @param denominator Denominator.
- /// @param target Value to calculate partial of.
- /// @return Partial value of target.
- function publicSafeGetPartialAmountFloor(
- uint256 numerator,
- uint256 denominator,
- uint256 target
- )
- public
- pure
- returns (uint256 partialAmount)
- {
- return safeGetPartialAmountFloor(numerator, denominator, target);
- }
-
- /// @dev Calculates partial value given a numerator and denominator.
- /// Reverts if rounding error is >= 0.1%
- /// @param numerator Numerator.
- /// @param denominator Denominator.
- /// @param target Value to calculate partial of.
- /// @return Partial value of target.
- function publicSafeGetPartialAmountCeil(
- uint256 numerator,
- uint256 denominator,
- uint256 target
- )
- public
- pure
- returns (uint256 partialAmount)
- {
- return safeGetPartialAmountCeil(numerator, denominator, target);
- }
-
- /// @dev Calculates partial value given a numerator and denominator.
- /// @param numerator Numerator.
- /// @param denominator Denominator.
- /// @param target Value to calculate partial of.
- /// @return Partial value of target.
- function publicGetPartialAmountFloor(
- uint256 numerator,
- uint256 denominator,
- uint256 target
- )
- public
- pure
- returns (uint256 partialAmount)
- {
- return getPartialAmountFloor(numerator, denominator, target);
- }
-
- /// @dev Calculates partial value given a numerator and denominator.
- /// @param numerator Numerator.
- /// @param denominator Denominator.
- /// @param target Value to calculate partial of.
- /// @return Partial value of target.
- function publicGetPartialAmountCeil(
- uint256 numerator,
- uint256 denominator,
- uint256 target
- )
- public
- pure
- returns (uint256 partialAmount)
- {
- return getPartialAmountCeil(numerator, denominator, target);
- }
-
- /// @dev Checks if rounding error >= 0.1%.
- /// @param numerator Numerator.
- /// @param denominator Denominator.
- /// @param target Value to multiply with numerator/denominator.
- /// @return Rounding error is present.
- function publicIsRoundingErrorFloor(
- uint256 numerator,
- uint256 denominator,
- uint256 target
- )
- public
- pure
- returns (bool isError)
- {
- return isRoundingErrorFloor(numerator, denominator, target);
- }
-
- /// @dev Checks if rounding error >= 0.1%.
- /// @param numerator Numerator.
- /// @param denominator Denominator.
- /// @param target Value to multiply with numerator/denominator.
- /// @return Rounding error is present.
- function publicIsRoundingErrorCeil(
- uint256 numerator,
- uint256 denominator,
- uint256 target
- )
- public
- pure
- returns (bool isError)
- {
- return isRoundingErrorCeil(numerator, denominator, target);
- }
-
- /// @dev Updates state with results of a fill order.
- /// @param order that was filled.
- /// @param takerAddress Address of taker who filled the order.
- /// @param orderTakerAssetFilledAmount Amount of order already filled.
- /// @return fillResults Amounts filled and fees paid by maker and taker.
- function publicUpdateFilledState(
- Order memory order,
- address takerAddress,
- bytes32 orderHash,
- uint256 orderTakerAssetFilledAmount,
- FillResults memory fillResults
- )
- public
- {
- updateFilledState(
- order,
- takerAddress,
- orderHash,
- orderTakerAssetFilledAmount,
- fillResults
- );
- }
-}
diff --git a/packages/contracts/contracts/test/TestLibBytes/TestLibBytes.sol b/packages/contracts/contracts/test/TestLibBytes/TestLibBytes.sol
deleted file mode 100644
index 00d861e61..000000000
--- a/packages/contracts/contracts/test/TestLibBytes/TestLibBytes.sol
+++ /dev/null
@@ -1,269 +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 "../../utils/LibBytes/LibBytes.sol";
-
-
-contract TestLibBytes {
-
- using LibBytes for bytes;
-
- /// @dev Pops the last byte off of a byte array by modifying its length.
- /// @param b Byte array that will be modified.
- /// @return The byte that was popped off.
- function publicPopLastByte(bytes memory b)
- public
- pure
- returns (bytes memory, bytes1 result)
- {
- result = b.popLastByte();
- return (b, result);
- }
-
- /// @dev Pops the last 20 bytes off of a byte array by modifying its length.
- /// @param b Byte array that will be modified.
- /// @return The 20 byte address that was popped off.
- function publicPopLast20Bytes(bytes memory b)
- public
- pure
- returns (bytes memory, address result)
- {
- result = b.popLast20Bytes();
- return (b, result);
- }
-
- /// @dev Tests equality of two byte arrays.
- /// @param lhs First byte array to compare.
- /// @param rhs Second byte array to compare.
- /// @return True if arrays are the same. False otherwise.
- function publicEquals(bytes memory lhs, bytes memory rhs)
- public
- pure
- returns (bool equal)
- {
- equal = lhs.equals(rhs);
- return equal;
- }
-
- function publicEqualsPop1(bytes memory lhs, bytes memory rhs)
- public
- pure
- returns (bool equal)
- {
- lhs.popLastByte();
- rhs.popLastByte();
- equal = lhs.equals(rhs);
- return equal;
- }
-
- /// @dev Performs a deep copy of a byte array onto another byte array of greater than or equal length.
- /// @param dest Byte array that will be overwritten with source bytes.
- /// @param source Byte array to copy onto dest bytes.
- function publicDeepCopyBytes(
- bytes memory dest,
- bytes memory source
- )
- public
- pure
- returns (bytes memory)
- {
- LibBytes.deepCopyBytes(dest, source);
- return dest;
- }
-
- /// @dev Reads an address from a position in a byte array.
- /// @param b Byte array containing an address.
- /// @param index Index in byte array of address.
- /// @return address from byte array.
- function publicReadAddress(
- bytes memory b,
- uint256 index
- )
- public
- pure
- returns (address result)
- {
- result = b.readAddress(index);
- return result;
- }
-
- /// @dev Writes an address into a specific position in a byte array.
- /// @param b Byte array to insert address into.
- /// @param index Index in byte array of address.
- /// @param input Address to put into byte array.
- function publicWriteAddress(
- bytes memory b,
- uint256 index,
- address input
- )
- public
- pure
- returns (bytes memory)
- {
- b.writeAddress(index, input);
- return b;
- }
-
- /// @dev Reads a bytes32 value from a position in a byte array.
- /// @param b Byte array containing a bytes32 value.
- /// @param index Index in byte array of bytes32 value.
- /// @return bytes32 value from byte array.
- function publicReadBytes32(
- bytes memory b,
- uint256 index
- )
- public
- pure
- returns (bytes32 result)
- {
- result = b.readBytes32(index);
- return result;
- }
-
- /// @dev Writes a bytes32 into a specific position in a byte array.
- /// @param b Byte array to insert <input> into.
- /// @param index Index in byte array of <input>.
- /// @param input bytes32 to put into byte array.
- function publicWriteBytes32(
- bytes memory b,
- uint256 index,
- bytes32 input
- )
- public
- pure
- returns (bytes memory)
- {
- b.writeBytes32(index, input);
- return b;
- }
-
- /// @dev Reads a uint256 value from a position in a byte array.
- /// @param b Byte array containing a uint256 value.
- /// @param index Index in byte array of uint256 value.
- /// @return uint256 value from byte array.
- function publicReadUint256(
- bytes memory b,
- uint256 index
- )
- public
- pure
- returns (uint256 result)
- {
- result = b.readUint256(index);
- return result;
- }
-
- /// @dev Writes a uint256 into a specific position in a byte array.
- /// @param b Byte array to insert <input> into.
- /// @param index Index in byte array of <input>.
- /// @param input uint256 to put into byte array.
- function publicWriteUint256(
- bytes memory b,
- uint256 index,
- uint256 input
- )
- public
- pure
- returns (bytes memory)
- {
- b.writeUint256(index, input);
- return b;
- }
-
- /// @dev Reads an unpadded bytes4 value from a position in a byte array.
- /// @param b Byte array containing a bytes4 value.
- /// @param index Index in byte array of bytes4 value.
- /// @return bytes4 value from byte array.
- function publicReadBytes4(
- bytes memory b,
- uint256 index
- )
- public
- pure
- returns (bytes4 result)
- {
- result = b.readBytes4(index);
- return result;
- }
-
- /// @dev Reads nested bytes from a specific position.
- /// @param b Byte array containing nested bytes.
- /// @param index Index of nested bytes.
- /// @return result Nested bytes.
- function publicReadBytesWithLength(
- bytes memory b,
- uint256 index
- )
- public
- pure
- returns (bytes memory result)
- {
- result = b.readBytesWithLength(index);
- return result;
- }
-
- /// @dev Inserts bytes at a specific position in a byte array.
- /// @param b Byte array to insert <input> into.
- /// @param index Index in byte array of <input>.
- /// @param input bytes to insert.
- /// @return b Updated input byte array
- function publicWriteBytesWithLength(
- bytes memory b,
- uint256 index,
- bytes memory input
- )
- public
- pure
- returns (bytes memory)
- {
- b.writeBytesWithLength(index, input);
- return b;
- }
-
- /// @dev Copies a block of memory from one location to another.
- /// @param mem Memory contents we want to apply memCopy to
- /// @param dest Destination offset into <mem>.
- /// @param source Source offset into <mem>.
- /// @param length Length of bytes to copy from <source> to <dest>
- /// @return mem Memory contents after calling memCopy.
- function testMemcpy(
- bytes mem,
- uint256 dest,
- uint256 source,
- uint256 length
- )
- public // not external, we need input in memory
- pure
- returns (bytes)
- {
- // Sanity check. Overflows are not checked.
- require(source + length <= mem.length);
- require(dest + length <= mem.length);
-
- // Get pointer to memory contents
- uint256 offset = mem.contentAddress();
-
- // Execute memCopy adjusted for memory array location
- LibBytes.memCopy(offset + dest, offset + source, length);
-
- // Return modified memory contents
- return mem;
- }
-}
diff --git a/packages/contracts/contracts/test/TestLibs/TestLibs.sol b/packages/contracts/contracts/test/TestLibs/TestLibs.sol
deleted file mode 100644
index a10f981fc..000000000
--- a/packages/contracts/contracts/test/TestLibs/TestLibs.sol
+++ /dev/null
@@ -1,152 +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 "../../protocol/Exchange/libs/LibMath.sol";
-import "../../protocol/Exchange/libs/LibOrder.sol";
-import "../../protocol/Exchange/libs/LibFillResults.sol";
-import "../../protocol/Exchange/libs/LibAbiEncoder.sol";
-
-
-contract TestLibs is
- LibMath,
- LibOrder,
- LibFillResults,
- LibAbiEncoder
-{
- function publicAbiEncodeFillOrder(
- Order memory order,
- uint256 takerAssetFillAmount,
- bytes memory signature
- )
- public
- pure
- returns (bytes memory fillOrderCalldata)
- {
- fillOrderCalldata = abiEncodeFillOrder(
- order,
- takerAssetFillAmount,
- signature
- );
- return fillOrderCalldata;
- }
-
- function publicGetPartialAmountFloor(
- uint256 numerator,
- uint256 denominator,
- uint256 target
- )
- public
- pure
- returns (uint256 partialAmount)
- {
- partialAmount = getPartialAmountFloor(
- numerator,
- denominator,
- target
- );
- return partialAmount;
- }
-
- function publicGetPartialAmountCeil(
- uint256 numerator,
- uint256 denominator,
- uint256 target
- )
- public
- pure
- returns (uint256 partialAmount)
- {
- partialAmount = getPartialAmountCeil(
- numerator,
- denominator,
- target
- );
- return partialAmount;
- }
-
- function publicIsRoundingErrorFloor(
- uint256 numerator,
- uint256 denominator,
- uint256 target
- )
- public
- pure
- returns (bool isError)
- {
- isError = isRoundingErrorFloor(
- numerator,
- denominator,
- target
- );
- return isError;
- }
-
- function publicIsRoundingErrorCeil(
- uint256 numerator,
- uint256 denominator,
- uint256 target
- )
- public
- pure
- returns (bool isError)
- {
- isError = isRoundingErrorCeil(
- numerator,
- denominator,
- target
- );
- return isError;
- }
-
- function publicGetOrderHash(Order memory order)
- public
- view
- returns (bytes32 orderHash)
- {
- orderHash = getOrderHash(order);
- return orderHash;
- }
-
- function getOrderSchemaHash()
- public
- pure
- returns (bytes32)
- {
- return EIP712_ORDER_SCHEMA_HASH;
- }
-
- function getDomainSeparatorSchemaHash()
- public
- pure
- returns (bytes32)
- {
- return EIP712_DOMAIN_SEPARATOR_SCHEMA_HASH;
- }
-
- function publicAddFillResults(FillResults memory totalFillResults, FillResults memory singleFillResults)
- public
- pure
- returns (FillResults memory)
- {
- addFillResults(totalFillResults, singleFillResults);
- return totalFillResults;
- }
-}
diff --git a/packages/contracts/contracts/test/TestSignatureValidator/TestSignatureValidator.sol b/packages/contracts/contracts/test/TestSignatureValidator/TestSignatureValidator.sol
deleted file mode 100644
index ea3e2de59..000000000
--- a/packages/contracts/contracts/test/TestSignatureValidator/TestSignatureValidator.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 "../../protocol/Exchange/MixinSignatureValidator.sol";
-import "../../protocol/Exchange/MixinTransactions.sol";
-
-
-contract TestSignatureValidator is
- MixinSignatureValidator,
- MixinTransactions
-{
- function publicIsValidSignature(
- bytes32 hash,
- address signer,
- bytes memory signature
- )
- public
- view
- returns (bool isValid)
- {
- isValid = isValidSignature(
- hash,
- signer,
- signature
- );
- return isValid;
- }
-}
diff --git a/packages/contracts/contracts/test/TestStaticCallReceiver/TestStaticCallReceiver.sol b/packages/contracts/contracts/test/TestStaticCallReceiver/TestStaticCallReceiver.sol
deleted file mode 100644
index 41aab01c8..000000000
--- a/packages/contracts/contracts/test/TestStaticCallReceiver/TestStaticCallReceiver.sol
+++ /dev/null
@@ -1,81 +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 "../../tokens/ERC20Token/IERC20Token.sol";
-
-
-// solhint-disable no-unused-vars
-contract TestStaticCallReceiver {
-
- uint256 internal state = 1;
-
- /// @dev Updates state and returns true. Intended to be used with `Validator` signature type.
- /// @param hash Message hash that is signed.
- /// @param signerAddress Address that should have signed the given hash.
- /// @param signature Proof of signing.
- /// @return Validity of order signature.
- function isValidSignature(
- bytes32 hash,
- address signerAddress,
- bytes signature
- )
- external
- returns (bool isValid)
- {
- updateState();
- return true;
- }
-
- /// @dev Updates state and returns true. Intended to be used with `Wallet` signature type.
- /// @param hash Message hash that is signed.
- /// @param signature Proof of signing.
- /// @return Validity of order signature.
- function isValidSignature(
- bytes32 hash,
- bytes signature
- )
- external
- returns (bool isValid)
- {
- updateState();
- return true;
- }
-
- /// @dev Approves an ERC20 token to spend tokens from this address.
- /// @param token Address of ERC20 token.
- /// @param spender Address that will spend tokens.
- /// @param value Amount of tokens spender is approved to spend.
- function approveERC20(
- address token,
- address spender,
- uint256 value
- )
- external
- {
- IERC20Token(token).approve(spender, value);
- }
-
- /// @dev Increments state variable.
- function updateState()
- internal
- {
- state++;
- }
-}
diff --git a/packages/contracts/contracts/tokens/ERC20Token/ERC20Token.sol b/packages/contracts/contracts/tokens/ERC20Token/ERC20Token.sol
deleted file mode 100644
index 725d304df..000000000
--- a/packages/contracts/contracts/tokens/ERC20Token/ERC20Token.sol
+++ /dev/null
@@ -1,148 +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 "./IERC20Token.sol";
-
-
-contract ERC20Token is
- IERC20Token
-{
- mapping (address => uint256) internal balances;
- mapping (address => mapping (address => uint256)) internal allowed;
-
- uint256 internal _totalSupply;
-
- /// @dev send `value` token to `to` from `msg.sender`
- /// @param _to The address of the recipient
- /// @param _value The amount of token to be transferred
- /// @return True if transfer was successful
- function transfer(address _to, uint256 _value)
- external
- returns (bool)
- {
- require(
- balances[msg.sender] >= _value,
- "ERC20_INSUFFICIENT_BALANCE"
- );
- require(
- balances[_to] + _value >= balances[_to],
- "UINT256_OVERFLOW"
- );
-
- balances[msg.sender] -= _value;
- balances[_to] += _value;
-
- emit Transfer(
- msg.sender,
- _to,
- _value
- );
-
- return true;
- }
-
- /// @dev send `value` token to `to` from `from` on the condition it is approved by `from`
- /// @param _from The address of the sender
- /// @param _to The address of the recipient
- /// @param _value The amount of token to be transferred
- /// @return True if transfer was successful
- function transferFrom(
- address _from,
- address _to,
- uint256 _value
- )
- external
- returns (bool)
- {
- require(
- balances[_from] >= _value,
- "ERC20_INSUFFICIENT_BALANCE"
- );
- require(
- allowed[_from][msg.sender] >= _value,
- "ERC20_INSUFFICIENT_ALLOWANCE"
- );
- require(
- balances[_to] + _value >= balances[_to],
- "UINT256_OVERFLOW"
- );
-
- balances[_to] += _value;
- balances[_from] -= _value;
- allowed[_from][msg.sender] -= _value;
-
- emit Transfer(
- _from,
- _to,
- _value
- );
-
- return true;
- }
-
- /// @dev `msg.sender` approves `_spender` to spend `_value` tokens
- /// @param _spender The address of the account able to transfer the tokens
- /// @param _value The amount of wei to be approved for transfer
- /// @return Always true if the call has enough gas to complete execution
- function approve(address _spender, uint256 _value)
- external
- returns (bool)
- {
- allowed[msg.sender][_spender] = _value;
- emit Approval(
- msg.sender,
- _spender,
- _value
- );
- return true;
- }
-
- /// @dev Query total supply of token
- /// @return Total supply of token
- function totalSupply()
- external
- view
- returns (uint256)
- {
- return _totalSupply;
- }
-
- /// @dev Query the balance of owner
- /// @param _owner The address from which the balance will be retrieved
- /// @return Balance of owner
- function balanceOf(address _owner)
- external
- view
- returns (uint256)
- {
- return balances[_owner];
- }
-
- /// @param _owner The address of the account owning tokens
- /// @param _spender The address of the account able to transfer the tokens
- /// @return Amount of remaining tokens allowed to spent
- function allowance(address _owner, address _spender)
- external
- view
- returns (uint256)
- {
- return allowed[_owner][_spender];
- }
-}
diff --git a/packages/contracts/contracts/tokens/ERC20Token/IERC20Token.sol b/packages/contracts/contracts/tokens/ERC20Token/IERC20Token.sol
deleted file mode 100644
index 258d47393..000000000
--- a/packages/contracts/contracts/tokens/ERC20Token/IERC20Token.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;
-
-
-contract IERC20Token {
-
- // solhint-disable no-simple-event-func-name
- event Transfer(
- address indexed _from,
- address indexed _to,
- uint256 _value
- );
-
- event Approval(
- address indexed _owner,
- address indexed _spender,
- uint256 _value
- );
-
- /// @dev send `value` token to `to` from `msg.sender`
- /// @param _to The address of the recipient
- /// @param _value The amount of token to be transferred
- /// @return True if transfer was successful
- function transfer(address _to, uint256 _value)
- external
- returns (bool);
-
- /// @dev send `value` token to `to` from `from` on the condition it is approved by `from`
- /// @param _from The address of the sender
- /// @param _to The address of the recipient
- /// @param _value The amount of token to be transferred
- /// @return True if transfer was successful
- function transferFrom(
- address _from,
- address _to,
- uint256 _value
- )
- external
- returns (bool);
-
- /// @dev `msg.sender` approves `_spender` to spend `_value` tokens
- /// @param _spender The address of the account able to transfer the tokens
- /// @param _value The amount of wei to be approved for transfer
- /// @return Always true if the call has enough gas to complete execution
- function approve(address _spender, uint256 _value)
- external
- returns (bool);
-
- /// @dev Query total supply of token
- /// @return Total supply of token
- function totalSupply()
- external
- view
- returns (uint256);
-
- /// @param _owner The address from which the balance will be retrieved
- /// @return Balance of owner
- function balanceOf(address _owner)
- external
- view
- returns (uint256);
-
- /// @param _owner The address of the account owning tokens
- /// @param _spender The address of the account able to transfer the tokens
- /// @return Amount of remaining tokens allowed to spent
- function allowance(address _owner, address _spender)
- external
- view
- returns (uint256);
-}
diff --git a/packages/contracts/contracts/tokens/ERC20Token/MintableERC20Token.sol b/packages/contracts/contracts/tokens/ERC20Token/MintableERC20Token.sol
deleted file mode 100644
index 9dc924422..000000000
--- a/packages/contracts/contracts/tokens/ERC20Token/MintableERC20Token.sol
+++ /dev/null
@@ -1,60 +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 "../../utils/SafeMath/SafeMath.sol";
-import "./UnlimitedAllowanceERC20Token.sol";
-
-
-contract MintableERC20Token is
- SafeMath,
- UnlimitedAllowanceERC20Token
-{
- /// @dev Mints new tokens
- /// @param _to Address of the beneficiary that will own the minted token
- /// @param _value Amount of tokens to mint
- function _mint(address _to, uint256 _value)
- internal
- {
- balances[_to] = safeAdd(_value, balances[_to]);
- _totalSupply = safeAdd(_totalSupply, _value);
-
- emit Transfer(
- address(0),
- _to,
- _value
- );
- }
-
- /// @dev Mints new tokens
- /// @param _owner Owner of tokens that will be burned
- /// @param _value Amount of tokens to burn
- function _burn(address _owner, uint256 _value)
- internal
- {
- balances[_owner] = safeSub(balances[_owner], _value);
- _totalSupply = safeSub(_totalSupply, _value);
-
- emit Transfer(
- _owner,
- address(0),
- _value
- );
- }
-}
diff --git a/packages/contracts/contracts/tokens/ERC20Token/UnlimitedAllowanceERC20Token.sol b/packages/contracts/contracts/tokens/ERC20Token/UnlimitedAllowanceERC20Token.sol
deleted file mode 100644
index 2e5bd4348..000000000
--- a/packages/contracts/contracts/tokens/ERC20Token/UnlimitedAllowanceERC20Token.sol
+++ /dev/null
@@ -1,70 +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 "../ERC20Token/ERC20Token.sol";
-
-
-contract UnlimitedAllowanceERC20Token is
- ERC20Token
-{
- uint256 constant internal MAX_UINT = 2**256 - 1;
-
- /// @dev ERC20 transferFrom, modified such that an allowance of MAX_UINT represents an unlimited allowance. See https://github.com/ethereum/EIPs/issues/717
- /// @param _from Address to transfer from.
- /// @param _to Address to transfer to.
- /// @param _value Amount to transfer.
- /// @return Success of transfer.
- function transferFrom(
- address _from,
- address _to,
- uint256 _value
- )
- external
- returns (bool)
- {
- uint256 allowance = allowed[_from][msg.sender];
- require(
- balances[_from] >= _value,
- "ERC20_INSUFFICIENT_BALANCE"
- );
- require(
- allowance >= _value,
- "ERC20_INSUFFICIENT_ALLOWANCE"
- );
- require(
- balances[_to] + _value >= balances[_to],
- "UINT256_OVERFLOW"
- );
-
- balances[_to] += _value;
- balances[_from] -= _value;
- if (allowance < MAX_UINT) {
- allowed[_from][msg.sender] -= _value;
- }
-
- emit Transfer(
- _from,
- _to,
- _value
- );
-
- return true;
- }
-}
diff --git a/packages/contracts/contracts/tokens/ERC721Token/ERC721Token.sol b/packages/contracts/contracts/tokens/ERC721Token/ERC721Token.sol
deleted file mode 100644
index 530f080c0..000000000
--- a/packages/contracts/contracts/tokens/ERC721Token/ERC721Token.sol
+++ /dev/null
@@ -1,277 +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 "./IERC721Token.sol";
-import "./IERC721Receiver.sol";
-import "../../utils/SafeMath/SafeMath.sol";
-
-
-contract ERC721Token is
- IERC721Token,
- SafeMath
-{
- // Function selector for ERC721Receiver.onERC721Received
- // 0x150b7a02
- bytes4 constant internal ERC721_RECEIVED = bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"));
-
- // Mapping of tokenId => owner
- mapping (uint256 => address) internal owners;
-
- // Mapping of tokenId => approved address
- mapping (uint256 => address) internal approvals;
-
- // Mapping of owner => number of tokens owned
- mapping (address => uint256) internal balances;
-
- // Mapping of owner => operator => approved
- mapping (address => mapping (address => bool)) internal operatorApprovals;
-
- /// @notice Transfers the ownership of an NFT from one address to another address
- /// @dev Throws unless `msg.sender` is the current owner, an authorized
- /// operator, or the approved address for this NFT. Throws if `_from` is
- /// not the current owner. Throws if `_to` is the zero address. Throws if
- /// `_tokenId` is not a valid NFT. When transfer is complete, this function
- /// checks if `_to` is a smart contract (code size > 0). If so, it calls
- /// `onERC721Received` on `_to` and throws if the return value is not
- /// `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`.
- /// @param _from The current owner of the NFT
- /// @param _to The new owner
- /// @param _tokenId The NFT to transfer
- /// @param _data Additional data with no specified format, sent in call to `_to`
- function safeTransferFrom(
- address _from,
- address _to,
- uint256 _tokenId,
- bytes _data
- )
- external
- {
- transferFrom(
- _from,
- _to,
- _tokenId
- );
-
- uint256 receiverCodeSize;
- assembly {
- receiverCodeSize := extcodesize(_to)
- }
- if (receiverCodeSize > 0) {
- bytes4 selector = IERC721Receiver(_to).onERC721Received(
- msg.sender,
- _from,
- _tokenId,
- _data
- );
- require(
- selector == ERC721_RECEIVED,
- "ERC721_INVALID_SELECTOR"
- );
- }
- }
-
- /// @notice Transfers the ownership of an NFT from one address to another address
- /// @dev This works identically to the other function with an extra data parameter,
- /// except this function just sets data to "".
- /// @param _from The current owner of the NFT
- /// @param _to The new owner
- /// @param _tokenId The NFT to transfer
- function safeTransferFrom(
- address _from,
- address _to,
- uint256 _tokenId
- )
- external
- {
- transferFrom(
- _from,
- _to,
- _tokenId
- );
-
- uint256 receiverCodeSize;
- assembly {
- receiverCodeSize := extcodesize(_to)
- }
- if (receiverCodeSize > 0) {
- bytes4 selector = IERC721Receiver(_to).onERC721Received(
- msg.sender,
- _from,
- _tokenId,
- ""
- );
- require(
- selector == ERC721_RECEIVED,
- "ERC721_INVALID_SELECTOR"
- );
- }
- }
-
- /// @notice Change or reaffirm the approved address for an NFT
- /// @dev The zero address indicates there is no approved address.
- /// Throws unless `msg.sender` is the current NFT owner, or an authorized
- /// operator of the current owner.
- /// @param _approved The new approved NFT controller
- /// @param _tokenId The NFT to approve
- function approve(address _approved, uint256 _tokenId)
- external
- {
- address owner = ownerOf(_tokenId);
- require(
- msg.sender == owner || isApprovedForAll(owner, msg.sender),
- "ERC721_INVALID_SENDER"
- );
-
- approvals[_tokenId] = _approved;
- emit Approval(
- owner,
- _approved,
- _tokenId
- );
- }
-
- /// @notice Enable or disable approval for a third party ("operator") to manage
- /// all of `msg.sender`'s assets
- /// @dev Emits the ApprovalForAll event. The contract MUST allow
- /// multiple operators per owner.
- /// @param _operator Address to add to the set of authorized operators
- /// @param _approved True if the operator is approved, false to revoke approval
- function setApprovalForAll(address _operator, bool _approved)
- external
- {
- operatorApprovals[msg.sender][_operator] = _approved;
- emit ApprovalForAll(
- msg.sender,
- _operator,
- _approved
- );
- }
-
- /// @notice Count all NFTs assigned to an owner
- /// @dev NFTs assigned to the zero address are considered invalid, and this
- /// function throws for queries about the zero address.
- /// @param _owner An address for whom to query the balance
- /// @return The number of NFTs owned by `_owner`, possibly zero
- function balanceOf(address _owner)
- external
- view
- returns (uint256)
- {
- require(
- _owner != address(0),
- "ERC721_ZERO_OWNER"
- );
- return balances[_owner];
- }
-
- /// @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE
- /// TO CONFIRM THAT `_to` IS CAPABLE OF RECEIVING NFTS OR ELSE
- /// THEY MAY BE PERMANENTLY LOST
- /// @dev Throws unless `msg.sender` is the current owner, an authorized
- /// operator, or the approved address for this NFT. Throws if `_from` is
- /// not the current owner. Throws if `_to` is the zero address. Throws if
- /// `_tokenId` is not a valid NFT.
- /// @param _from The current owner of the NFT
- /// @param _to The new owner
- /// @param _tokenId The NFT to transfer
- function transferFrom(
- address _from,
- address _to,
- uint256 _tokenId
- )
- public
- {
- require(
- _to != address(0),
- "ERC721_ZERO_TO_ADDRESS"
- );
-
- address owner = ownerOf(_tokenId);
- require(
- _from == owner,
- "ERC721_OWNER_MISMATCH"
- );
-
- address spender = msg.sender;
- address approvedAddress = getApproved(_tokenId);
- require(
- spender == owner ||
- isApprovedForAll(owner, spender) ||
- approvedAddress == spender,
- "ERC721_INVALID_SPENDER"
- );
-
- if (approvedAddress != address(0)) {
- approvals[_tokenId] = address(0);
- }
-
- owners[_tokenId] = _to;
- balances[_from] = safeSub(balances[_from], 1);
- balances[_to] = safeAdd(balances[_to], 1);
-
- emit Transfer(
- _from,
- _to,
- _tokenId
- );
- }
-
- /// @notice Find the owner of an NFT
- /// @dev NFTs assigned to zero address are considered invalid, and queries
- /// about them do throw.
- /// @param _tokenId The identifier for an NFT
- /// @return The address of the owner of the NFT
- function ownerOf(uint256 _tokenId)
- public
- view
- returns (address)
- {
- address owner = owners[_tokenId];
- require(
- owner != address(0),
- "ERC721_ZERO_OWNER"
- );
- return owner;
- }
-
- /// @notice Get the approved address for a single NFT
- /// @dev Throws if `_tokenId` is not a valid NFT.
- /// @param _tokenId The NFT to find the approved address for
- /// @return The approved address for this NFT, or the zero address if there is none
- function getApproved(uint256 _tokenId)
- public
- view
- returns (address)
- {
- return approvals[_tokenId];
- }
-
- /// @notice Query if an address is an authorized operator for another address
- /// @param _owner The address that owns the NFTs
- /// @param _operator The address that acts on behalf of the owner
- /// @return True if `_operator` is an approved operator for `_owner`, false otherwise
- function isApprovedForAll(address _owner, address _operator)
- public
- view
- returns (bool)
- {
- return operatorApprovals[_owner][_operator];
- }
-}
diff --git a/packages/contracts/contracts/tokens/ERC721Token/IERC721Receiver.sol b/packages/contracts/contracts/tokens/ERC721Token/IERC721Receiver.sol
deleted file mode 100644
index 8e0e32ab2..000000000
--- a/packages/contracts/contracts/tokens/ERC721Token/IERC721Receiver.sol
+++ /dev/null
@@ -1,44 +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 IERC721Receiver {
-
- /// @notice Handle the receipt of an NFT
- /// @dev The ERC721 smart contract calls this function on the recipient
- /// after a `transfer`. This function MAY throw to revert and reject the
- /// transfer. Return of other than the magic value MUST result in the
- /// transaction being reverted.
- /// Note: the contract address is always the message sender.
- /// @param _operator The address which called `safeTransferFrom` function
- /// @param _from The address which previously owned the token
- /// @param _tokenId The NFT identifier which is being transferred
- /// @param _data Additional data with no specified format
- /// @return `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
- /// unless throwing
- function onERC721Received(
- address _operator,
- address _from,
- uint256 _tokenId,
- bytes _data
- )
- external
- returns (bytes4);
-}
diff --git a/packages/contracts/contracts/tokens/ERC721Token/IERC721Token.sol b/packages/contracts/contracts/tokens/ERC721Token/IERC721Token.sol
deleted file mode 100644
index ac992c80d..000000000
--- a/packages/contracts/contracts/tokens/ERC721Token/IERC721Token.sol
+++ /dev/null
@@ -1,158 +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 IERC721Token {
-
- /// @dev This emits when ownership of any NFT changes by any mechanism.
- /// This event emits when NFTs are created (`from` == 0) and destroyed
- /// (`to` == 0). Exception: during contract creation, any number of NFTs
- /// may be created and assigned without emitting Transfer. At the time of
- /// any transfer, the approved address for that NFT (if any) is reset to none.
- event Transfer(
- address indexed _from,
- address indexed _to,
- uint256 indexed _tokenId
- );
-
- /// @dev This emits when the approved address for an NFT is changed or
- /// reaffirmed. The zero address indicates there is no approved address.
- /// When a Transfer event emits, this also indicates that the approved
- /// address for that NFT (if any) is reset to none.
- event Approval(
- address indexed _owner,
- address indexed _approved,
- uint256 indexed _tokenId
- );
-
- /// @dev This emits when an operator is enabled or disabled for an owner.
- /// The operator can manage all NFTs of the owner.
- event ApprovalForAll(
- address indexed _owner,
- address indexed _operator,
- bool _approved
- );
-
- /// @notice Transfers the ownership of an NFT from one address to another address
- /// @dev Throws unless `msg.sender` is the current owner, an authorized
- /// perator, or the approved address for this NFT. Throws if `_from` is
- /// not the current owner. Throws if `_to` is the zero address. Throws if
- /// `_tokenId` is not a valid NFT. When transfer is complete, this function
- /// checks if `_to` is a smart contract (code size > 0). If so, it calls
- /// `onERC721Received` on `_to` and throws if the return value is not
- /// `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`.
- /// @param _from The current owner of the NFT
- /// @param _to The new owner
- /// @param _tokenId The NFT to transfer
- /// @param _data Additional data with no specified format, sent in call to `_to`
- function safeTransferFrom(
- address _from,
- address _to,
- uint256 _tokenId,
- bytes _data
- )
- external;
-
- /// @notice Transfers the ownership of an NFT from one address to another address
- /// @dev This works identically to the other function with an extra data parameter,
- /// except this function just sets data to "".
- /// @param _from The current owner of the NFT
- /// @param _to The new owner
- /// @param _tokenId The NFT to transfer
- function safeTransferFrom(
- address _from,
- address _to,
- uint256 _tokenId
- )
- external;
-
- /// @notice Change or reaffirm the approved address for an NFT
- /// @dev The zero address indicates there is no approved address.
- /// Throws unless `msg.sender` is the current NFT owner, or an authorized
- /// operator of the current owner.
- /// @param _approved The new approved NFT controller
- /// @param _tokenId The NFT to approve
- function approve(address _approved, uint256 _tokenId)
- external;
-
- /// @notice Enable or disable approval for a third party ("operator") to manage
- /// all of `msg.sender`'s assets
- /// @dev Emits the ApprovalForAll event. The contract MUST allow
- /// multiple operators per owner.
- /// @param _operator Address to add to the set of authorized operators
- /// @param _approved True if the operator is approved, false to revoke approval
- function setApprovalForAll(address _operator, bool _approved)
- external;
-
- /// @notice Count all NFTs assigned to an owner
- /// @dev NFTs assigned to the zero address are considered invalid, and this
- /// function throws for queries about the zero address.
- /// @param _owner An address for whom to query the balance
- /// @return The number of NFTs owned by `_owner`, possibly zero
- function balanceOf(address _owner)
- external
- view
- returns (uint256);
-
- /// @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE
- /// TO CONFIRM THAT `_to` IS CAPABLE OF RECEIVING NFTS OR ELSE
- /// THEY MAY BE PERMANENTLY LOST
- /// @dev Throws unless `msg.sender` is the current owner, an authorized
- /// operator, or the approved address for this NFT. Throws if `_from` is
- /// not the current owner. Throws if `_to` is the zero address. Throws if
- /// `_tokenId` is not a valid NFT.
- /// @param _from The current owner of the NFT
- /// @param _to The new owner
- /// @param _tokenId The NFT to transfer
- function transferFrom(
- address _from,
- address _to,
- uint256 _tokenId
- )
- public;
-
- /// @notice Find the owner of an NFT
- /// @dev NFTs assigned to zero address are considered invalid, and queries
- /// about them do throw.
- /// @param _tokenId The identifier for an NFT
- /// @return The address of the owner of the NFT
- function ownerOf(uint256 _tokenId)
- public
- view
- returns (address);
-
- /// @notice Get the approved address for a single NFT
- /// @dev Throws if `_tokenId` is not a valid NFT.
- /// @param _tokenId The NFT to find the approved address for
- /// @return The approved address for this NFT, or the zero address if there is none
- function getApproved(uint256 _tokenId)
- public
- view
- returns (address);
-
- /// @notice Query if an address is an authorized operator for another address
- /// @param _owner The address that owns the NFTs
- /// @param _operator The address that acts on behalf of the owner
- /// @return True if `_operator` is an approved operator for `_owner`, false otherwise
- function isApprovedForAll(address _owner, address _operator)
- public
- view
- returns (bool);
-}
diff --git a/packages/contracts/contracts/tokens/ERC721Token/MintableERC721Token.sol b/packages/contracts/contracts/tokens/ERC721Token/MintableERC721Token.sol
deleted file mode 100644
index bc5cd2cc2..000000000
--- a/packages/contracts/contracts/tokens/ERC721Token/MintableERC721Token.sol
+++ /dev/null
@@ -1,82 +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 "./ERC721Token.sol";
-
-
-contract MintableERC721Token is
- ERC721Token
-{
- /// @dev Function to mint a new token
- /// Reverts if the given token ID already exists
- /// @param _to Address of the beneficiary that will own the minted token
- /// @param _tokenId ID of the token to be minted by the msg.sender
- function _mint(address _to, uint256 _tokenId)
- internal
- {
- require(
- _to != address(0),
- "ERC721_ZERO_TO_ADDRESS"
- );
-
- address owner = owners[_tokenId];
- require(
- owner == address(0),
- "ERC721_OWNER_ALREADY_EXISTS"
- );
-
- owners[_tokenId] = _to;
- balances[_to] = safeAdd(balances[_to], 1);
-
- emit Transfer(
- address(0),
- _to,
- _tokenId
- );
- }
-
- /// @dev Function to burn a token
- /// Reverts if the given token ID doesn't exist
- /// @param _owner Owner of token with given token ID
- /// @param _tokenId ID of the token to be burned by the msg.sender
- function _burn(address _owner, uint256 _tokenId)
- internal
- {
- require(
- _owner != address(0),
- "ERC721_ZERO_OWNER_ADDRESS"
- );
-
- address owner = owners[_tokenId];
- require(
- owner == _owner,
- "ERC721_OWNER_MISMATCH"
- );
-
- owners[_tokenId] = address(0);
- balances[_owner] = safeSub(balances[_owner], 1);
-
- emit Transfer(
- _owner,
- address(0),
- _tokenId
- );
- }
-}
diff --git a/packages/contracts/contracts/tokens/EtherToken/IEtherToken.sol b/packages/contracts/contracts/tokens/EtherToken/IEtherToken.sol
deleted file mode 100644
index 9e2e68766..000000000
--- a/packages/contracts/contracts/tokens/EtherToken/IEtherToken.sol
+++ /dev/null
@@ -1,33 +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 "../ERC20Token/IERC20Token.sol";
-
-
-contract IEtherToken is
- IERC20Token
-{
- function deposit()
- public
- payable;
-
- function withdraw(uint256 amount)
- public;
-}
diff --git a/packages/contracts/contracts/tokens/EtherToken/WETH9.sol b/packages/contracts/contracts/tokens/EtherToken/WETH9.sol
deleted file mode 100644
index 17876b86d..000000000
--- a/packages/contracts/contracts/tokens/EtherToken/WETH9.sol
+++ /dev/null
@@ -1,758 +0,0 @@
-// Copyright (C) 2015, 2016, 2017 Dapphub
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-// solhint-disable
-pragma solidity ^0.4.18;
-
-
-contract WETH9 {
- string public name = "Wrapped Ether";
- string public symbol = "WETH";
- uint8 public decimals = 18;
-
- event Approval(address indexed _owner, address indexed _spender, uint _value);
- event Transfer(address indexed _from, address indexed _to, uint _value);
- event Deposit(address indexed _owner, uint _value);
- event Withdrawal(address indexed _owner, uint _value);
-
- mapping (address => uint) public balanceOf;
- mapping (address => mapping (address => uint)) public allowance;
-
- function() public payable {
- deposit();
- }
- function deposit() public payable {
- balanceOf[msg.sender] += msg.value;
- Deposit(msg.sender, msg.value);
- }
- function withdraw(uint wad) public {
- require(balanceOf[msg.sender] >= wad);
- balanceOf[msg.sender] -= wad;
- msg.sender.transfer(wad);
- Withdrawal(msg.sender, wad);
- }
-
- function totalSupply() public view returns (uint) {
- return this.balance;
- }
-
- function approve(address guy, uint wad) public returns (bool) {
- allowance[msg.sender][guy] = wad;
- Approval(msg.sender, guy, wad);
- return true;
- }
-
- function transfer(address dst, uint wad) public returns (bool) {
- return transferFrom(msg.sender, dst, wad);
- }
-
- function transferFrom(address src, address dst, uint wad)
- public
- returns (bool)
- {
- require(balanceOf[src] >= wad);
-
- if (src != msg.sender && allowance[src][msg.sender] != uint(-1)) {
- require(allowance[src][msg.sender] >= wad);
- allowance[src][msg.sender] -= wad;
- }
-
- balanceOf[src] -= wad;
- balanceOf[dst] += wad;
-
- Transfer(src, dst, wad);
-
- return true;
- }
-}
-
-
-/*
- GNU GENERAL PUBLIC LICENSE
- Version 3, 29 June 2007
-
- Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
- Preamble
-
- The GNU General Public License is a free, copyleft license for
-software and other kinds of works.
-
- The licenses for most software and other practical works are designed
-to take away your freedom to share and change the works. By contrast,
-the GNU General Public License is intended to guarantee your freedom to
-share and change all versions of a program--to make sure it remains free
-software for all its users. We, the Free Software Foundation, use the
-GNU General Public License for most of our software; it applies also to
-any other work released this way by its authors. You can apply it to
-your programs, too.
-
- When we speak of free software, we are referring to freedom, not
-price. Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-them if you wish), that you receive source code or can get it if you
-want it, that you can change the software or use pieces of it in new
-free programs, and that you know you can do these things.
-
- To protect your rights, we need to prevent others from denying you
-these rights or asking you to surrender the rights. Therefore, you have
-certain responsibilities if you distribute copies of the software, or if
-you modify it: responsibilities to respect the freedom of others.
-
- For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must pass on to the recipients the same
-freedoms that you received. You must make sure that they, too, receive
-or can get the source code. And you must show them these terms so they
-know their rights.
-
- Developers that use the GNU GPL protect your rights with two steps:
-(1) assert copyright on the software, and (2) offer you this License
-giving you legal permission to copy, distribute and/or modify it.
-
- For the developers' and authors' protection, the GPL clearly explains
-that there is no warranty for this free software. For both users' and
-authors' sake, the GPL requires that modified versions be marked as
-changed, so that their problems will not be attributed erroneously to
-authors of previous versions.
-
- Some devices are designed to deny users access to install or run
-modified versions of the software inside them, although the manufacturer
-can do so. This is fundamentally incompatible with the aim of
-protecting users' freedom to change the software. The systematic
-pattern of such abuse occurs in the area of products for individuals to
-use, which is precisely where it is most unacceptable. Therefore, we
-have designed this version of the GPL to prohibit the practice for those
-products. If such problems arise substantially in other domains, we
-stand ready to extend this provision to those domains in future versions
-of the GPL, as needed to protect the freedom of users.
-
- Finally, every program is threatened constantly by software patents.
-States should not allow patents to restrict development and use of
-software on general-purpose computers, but in those that do, we wish to
-avoid the special danger that patents applied to a free program could
-make it effectively proprietary. To prevent this, the GPL assures that
-patents cannot be used to render the program non-free.
-
- The precise terms and conditions for copying, distribution and
-modification follow.
-
- TERMS AND CONDITIONS
-
- 0. Definitions.
-
- "This License" refers to version 3 of the GNU General Public License.
-
- "Copyright" also means copyright-like laws that apply to other kinds of
-works, such as semiconductor masks.
-
- "The Program" refers to any copyrightable work licensed under this
-License. Each licensee is addressed as "you". "Licensees" and
-"recipients" may be individuals or organizations.
-
- To "modify" a work means to copy from or adapt all or part of the work
-in a fashion requiring copyright permission, other than the making of an
-exact copy. The resulting work is called a "modified version" of the
-earlier work or a work "based on" the earlier work.
-
- A "covered work" means either the unmodified Program or a work based
-on the Program.
-
- To "propagate" a work means to do anything with it that, without
-permission, would make you directly or secondarily liable for
-infringement under applicable copyright law, except executing it on a
-computer or modifying a private copy. Propagation includes copying,
-distribution (with or without modification), making available to the
-public, and in some countries other activities as well.
-
- To "convey" a work means any kind of propagation that enables other
-parties to make or receive copies. Mere interaction with a user through
-a computer network, with no transfer of a copy, is not conveying.
-
- An interactive user interface displays "Appropriate Legal Notices"
-to the extent that it includes a convenient and prominently visible
-feature that (1) displays an appropriate copyright notice, and (2)
-tells the user that there is no warranty for the work (except to the
-extent that warranties are provided), that licensees may convey the
-work under this License, and how to view a copy of this License. If
-the interface presents a list of user commands or options, such as a
-menu, a prominent item in the list meets this criterion.
-
- 1. Source Code.
-
- The "source code" for a work means the preferred form of the work
-for making modifications to it. "Object code" means any non-source
-form of a work.
-
- A "Standard Interface" means an interface that either is an official
-standard defined by a recognized standards body, or, in the case of
-interfaces specified for a particular programming language, one that
-is widely used among developers working in that language.
-
- The "System Libraries" of an executable work include anything, other
-than the work as a whole, that (a) is included in the normal form of
-packaging a Major Component, but which is not part of that Major
-Component, and (b) serves only to enable use of the work with that
-Major Component, or to implement a Standard Interface for which an
-implementation is available to the public in source code form. A
-"Major Component", in this context, means a major essential component
-(kernel, window system, and so on) of the specific operating system
-(if any) on which the executable work runs, or a compiler used to
-produce the work, or an object code interpreter used to run it.
-
- The "Corresponding Source" for a work in object code form means all
-the source code needed to generate, install, and (for an executable
-work) run the object code and to modify the work, including scripts to
-control those activities. However, it does not include the work's
-System Libraries, or general-purpose tools or generally available free
-programs which are used unmodified in performing those activities but
-which are not part of the work. For example, Corresponding Source
-includes interface definition files associated with source files for
-the work, and the source code for shared libraries and dynamically
-linked subprograms that the work is specifically designed to require,
-such as by intimate data communication or control flow between those
-subprograms and other parts of the work.
-
- The Corresponding Source need not include anything that users
-can regenerate automatically from other parts of the Corresponding
-Source.
-
- The Corresponding Source for a work in source code form is that
-same work.
-
- 2. Basic Permissions.
-
- All rights granted under this License are granted for the term of
-copyright on the Program, and are irrevocable provided the stated
-conditions are met. This License explicitly affirms your unlimited
-permission to run the unmodified Program. The output from running a
-covered work is covered by this License only if the output, given its
-content, constitutes a covered work. This License acknowledges your
-rights of fair use or other equivalent, as provided by copyright law.
-
- You may make, run and propagate covered works that you do not
-convey, without conditions so long as your license otherwise remains
-in force. You may convey covered works to others for the sole purpose
-of having them make modifications exclusively for you, or provide you
-with facilities for running those works, provided that you comply with
-the terms of this License in conveying all material for which you do
-not control copyright. Those thus making or running the covered works
-for you must do so exclusively on your behalf, under your direction
-and control, on terms that prohibit them from making any copies of
-your copyrighted material outside their relationship with you.
-
- Conveying under any other circumstances is permitted solely under
-the conditions stated below. Sublicensing is not allowed; section 10
-makes it unnecessary.
-
- 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
-
- No covered work shall be deemed part of an effective technological
-measure under any applicable law fulfilling obligations under article
-11 of the WIPO copyright treaty adopted on 20 December 1996, or
-similar laws prohibiting or restricting circumvention of such
-measures.
-
- When you convey a covered work, you waive any legal power to forbid
-circumvention of technological measures to the extent such circumvention
-is effected by exercising rights under this License with respect to
-the covered work, and you disclaim any intention to limit operation or
-modification of the work as a means of enforcing, against the work's
-users, your or third parties' legal rights to forbid circumvention of
-technological measures.
-
- 4. Conveying Verbatim Copies.
-
- You may convey verbatim copies of the Program's source code as you
-receive it, in any medium, provided that you conspicuously and
-appropriately publish on each copy an appropriate copyright notice;
-keep intact all notices stating that this License and any
-non-permissive terms added in accord with section 7 apply to the code;
-keep intact all notices of the absence of any warranty; and give all
-recipients a copy of this License along with the Program.
-
- You may charge any price or no price for each copy that you convey,
-and you may offer support or warranty protection for a fee.
-
- 5. Conveying Modified Source Versions.
-
- You may convey a work based on the Program, or the modifications to
-produce it from the Program, in the form of source code under the
-terms of section 4, provided that you also meet all of these conditions:
-
- a) The work must carry prominent notices stating that you modified
- it, and giving a relevant date.
-
- b) The work must carry prominent notices stating that it is
- released under this License and any conditions added under section
- 7. This requirement modifies the requirement in section 4 to
- "keep intact all notices".
-
- c) You must license the entire work, as a whole, under this
- License to anyone who comes into possession of a copy. This
- License will therefore apply, along with any applicable section 7
- additional terms, to the whole of the work, and all its parts,
- regardless of how they are packaged. This License gives no
- permission to license the work in any other way, but it does not
- invalidate such permission if you have separately received it.
-
- d) If the work has interactive user interfaces, each must display
- Appropriate Legal Notices; however, if the Program has interactive
- interfaces that do not display Appropriate Legal Notices, your
- work need not make them do so.
-
- A compilation of a covered work with other separate and independent
-works, which are not by their nature extensions of the covered work,
-and which are not combined with it such as to form a larger program,
-in or on a volume of a storage or distribution medium, is called an
-"aggregate" if the compilation and its resulting copyright are not
-used to limit the access or legal rights of the compilation's users
-beyond what the individual works permit. Inclusion of a covered work
-in an aggregate does not cause this License to apply to the other
-parts of the aggregate.
-
- 6. Conveying Non-Source Forms.
-
- You may convey a covered work in object code form under the terms
-of sections 4 and 5, provided that you also convey the
-machine-readable Corresponding Source under the terms of this License,
-in one of these ways:
-
- a) Convey the object code in, or embodied in, a physical product
- (including a physical distribution medium), accompanied by the
- Corresponding Source fixed on a durable physical medium
- customarily used for software interchange.
-
- b) Convey the object code in, or embodied in, a physical product
- (including a physical distribution medium), accompanied by a
- written offer, valid for at least three years and valid for as
- long as you offer spare parts or customer support for that product
- model, to give anyone who possesses the object code either (1) a
- copy of the Corresponding Source for all the software in the
- product that is covered by this License, on a durable physical
- medium customarily used for software interchange, for a price no
- more than your reasonable cost of physically performing this
- conveying of source, or (2) access to copy the
- Corresponding Source from a network server at no charge.
-
- c) Convey individual copies of the object code with a copy of the
- written offer to provide the Corresponding Source. This
- alternative is allowed only occasionally and noncommercially, and
- only if you received the object code with such an offer, in accord
- with subsection 6b.
-
- d) Convey the object code by offering access from a designated
- place (gratis or for a charge), and offer equivalent access to the
- Corresponding Source in the same way through the same place at no
- further charge. You need not require recipients to copy the
- Corresponding Source along with the object code. If the place to
- copy the object code is a network server, the Corresponding Source
- may be on a different server (operated by you or a third party)
- that supports equivalent copying facilities, provided you maintain
- clear directions next to the object code saying where to find the
- Corresponding Source. Regardless of what server hosts the
- Corresponding Source, you remain obligated to ensure that it is
- available for as long as needed to satisfy these requirements.
-
- e) Convey the object code using peer-to-peer transmission, provided
- you inform other peers where the object code and Corresponding
- Source of the work are being offered to the general public at no
- charge under subsection 6d.
-
- A separable portion of the object code, whose source code is excluded
-from the Corresponding Source as a System Library, need not be
-included in conveying the object code work.
-
- A "User Product" is either (1) a "consumer product", which means any
-tangible personal property which is normally used for personal, family,
-or household purposes, or (2) anything designed or sold for incorporation
-into a dwelling. In determining whether a product is a consumer product,
-doubtful cases shall be resolved in favor of coverage. For a particular
-product received by a particular user, "normally used" refers to a
-typical or common use of that class of product, regardless of the status
-of the particular user or of the way in which the particular user
-actually uses, or expects or is expected to use, the product. A product
-is a consumer product regardless of whether the product has substantial
-commercial, industrial or non-consumer uses, unless such uses represent
-the only significant mode of use of the product.
-
- "Installation Information" for a User Product means any methods,
-procedures, authorization keys, or other information required to install
-and execute modified versions of a covered work in that User Product from
-a modified version of its Corresponding Source. The information must
-suffice to ensure that the continued functioning of the modified object
-code is in no case prevented or interfered with solely because
-modification has been made.
-
- If you convey an object code work under this section in, or with, or
-specifically for use in, a User Product, and the conveying occurs as
-part of a transaction in which the right of possession and use of the
-User Product is transferred to the recipient in perpetuity or for a
-fixed term (regardless of how the transaction is characterized), the
-Corresponding Source conveyed under this section must be accompanied
-by the Installation Information. But this requirement does not apply
-if neither you nor any third party retains the ability to install
-modified object code on the User Product (for example, the work has
-been installed in ROM).
-
- The requirement to provide Installation Information does not include a
-requirement to continue to provide support service, warranty, or updates
-for a work that has been modified or installed by the recipient, or for
-the User Product in which it has been modified or installed. Access to a
-network may be denied when the modification itself materially and
-adversely affects the operation of the network or violates the rules and
-protocols for communication across the network.
-
- Corresponding Source conveyed, and Installation Information provided,
-in accord with this section must be in a format that is publicly
-documented (and with an implementation available to the public in
-source code form), and must require no special password or key for
-unpacking, reading or copying.
-
- 7. Additional Terms.
-
- "Additional permissions" are terms that supplement the terms of this
-License by making exceptions from one or more of its conditions.
-Additional permissions that are applicable to the entire Program shall
-be treated as though they were included in this License, to the extent
-that they are valid under applicable law. If additional permissions
-apply only to part of the Program, that part may be used separately
-under those permissions, but the entire Program remains governed by
-this License without regard to the additional permissions.
-
- When you convey a copy of a covered work, you may at your option
-remove any additional permissions from that copy, or from any part of
-it. (Additional permissions may be written to require their own
-removal in certain cases when you modify the work.) You may place
-additional permissions on material, added by you to a covered work,
-for which you have or can give appropriate copyright permission.
-
- Notwithstanding any other provision of this License, for material you
-add to a covered work, you may (if authorized by the copyright holders of
-that material) supplement the terms of this License with terms:
-
- a) Disclaiming warranty or limiting liability differently from the
- terms of sections 15 and 16 of this License; or
-
- b) Requiring preservation of specified reasonable legal notices or
- author attributions in that material or in the Appropriate Legal
- Notices displayed by works containing it; or
-
- c) Prohibiting misrepresentation of the origin of that material, or
- requiring that modified versions of such material be marked in
- reasonable ways as different from the original version; or
-
- d) Limiting the use for publicity purposes of names of licensors or
- authors of the material; or
-
- e) Declining to grant rights under trademark law for use of some
- trade names, trademarks, or service marks; or
-
- f) Requiring indemnification of licensors and authors of that
- material by anyone who conveys the material (or modified versions of
- it) with contractual assumptions of liability to the recipient, for
- any liability that these contractual assumptions directly impose on
- those licensors and authors.
-
- All other non-permissive additional terms are considered "further
-restrictions" within the meaning of section 10. If the Program as you
-received it, or any part of it, contains a notice stating that it is
-governed by this License along with a term that is a further
-restriction, you may remove that term. If a license document contains
-a further restriction but permits relicensing or conveying under this
-License, you may add to a covered work material governed by the terms
-of that license document, provided that the further restriction does
-not survive such relicensing or conveying.
-
- If you add terms to a covered work in accord with this section, you
-must place, in the relevant source files, a statement of the
-additional terms that apply to those files, or a notice indicating
-where to find the applicable terms.
-
- Additional terms, permissive or non-permissive, may be stated in the
-form of a separately written license, or stated as exceptions;
-the above requirements apply either way.
-
- 8. Termination.
-
- You may not propagate or modify a covered work except as expressly
-provided under this License. Any attempt otherwise to propagate or
-modify it is void, and will automatically terminate your rights under
-this License (including any patent licenses granted under the third
-paragraph of section 11).
-
- However, if you cease all violation of this License, then your
-license from a particular copyright holder is reinstated (a)
-provisionally, unless and until the copyright holder explicitly and
-finally terminates your license, and (b) permanently, if the copyright
-holder fails to notify you of the violation by some reasonable means
-prior to 60 days after the cessation.
-
- Moreover, your license from a particular copyright holder is
-reinstated permanently if the copyright holder notifies you of the
-violation by some reasonable means, this is the first time you have
-received notice of violation of this License (for any work) from that
-copyright holder, and you cure the violation prior to 30 days after
-your receipt of the notice.
-
- Termination of your rights under this section does not terminate the
-licenses of parties who have received copies or rights from you under
-this License. If your rights have been terminated and not permanently
-reinstated, you do not qualify to receive new licenses for the same
-material under section 10.
-
- 9. Acceptance Not Required for Having Copies.
-
- You are not required to accept this License in order to receive or
-run a copy of the Program. Ancillary propagation of a covered work
-occurring solely as a consequence of using peer-to-peer transmission
-to receive a copy likewise does not require acceptance. However,
-nothing other than this License grants you permission to propagate or
-modify any covered work. These actions infringe copyright if you do
-not accept this License. Therefore, by modifying or propagating a
-covered work, you indicate your acceptance of this License to do so.
-
- 10. Automatic Licensing of Downstream Recipients.
-
- Each time you convey a covered work, the recipient automatically
-receives a license from the original licensors, to run, modify and
-propagate that work, subject to this License. You are not responsible
-for enforcing compliance by third parties with this License.
-
- An "entity transaction" is a transaction transferring control of an
-organization, or substantially all assets of one, or subdividing an
-organization, or merging organizations. If propagation of a covered
-work results from an entity transaction, each party to that
-transaction who receives a copy of the work also receives whatever
-licenses to the work the party's predecessor in interest had or could
-give under the previous paragraph, plus a right to possession of the
-Corresponding Source of the work from the predecessor in interest, if
-the predecessor has it or can get it with reasonable efforts.
-
- You may not impose any further restrictions on the exercise of the
-rights granted or affirmed under this License. For example, you may
-not impose a license fee, royalty, or other charge for exercise of
-rights granted under this License, and you may not initiate litigation
-(including a cross-claim or counterclaim in a lawsuit) alleging that
-any patent claim is infringed by making, using, selling, offering for
-sale, or importing the Program or any portion of it.
-
- 11. Patents.
-
- A "contributor" is a copyright holder who authorizes use under this
-License of the Program or a work on which the Program is based. The
-work thus licensed is called the contributor's "contributor version".
-
- A contributor's "essential patent claims" are all patent claims
-owned or controlled by the contributor, whether already acquired or
-hereafter acquired, that would be infringed by some manner, permitted
-by this License, of making, using, or selling its contributor version,
-but do not include claims that would be infringed only as a
-consequence of further modification of the contributor version. For
-purposes of this definition, "control" includes the right to grant
-patent sublicenses in a manner consistent with the requirements of
-this License.
-
- Each contributor grants you a non-exclusive, worldwide, royalty-free
-patent license under the contributor's essential patent claims, to
-make, use, sell, offer for sale, import and otherwise run, modify and
-propagate the contents of its contributor version.
-
- In the following three paragraphs, a "patent license" is any express
-agreement or commitment, however denominated, not to enforce a patent
-(such as an express permission to practice a patent or covenant not to
-sue for patent infringement). To "grant" such a patent license to a
-party means to make such an agreement or commitment not to enforce a
-patent against the party.
-
- If you convey a covered work, knowingly relying on a patent license,
-and the Corresponding Source of the work is not available for anyone
-to copy, free of charge and under the terms of this License, through a
-publicly available network server or other readily accessible means,
-then you must either (1) cause the Corresponding Source to be so
-available, or (2) arrange to deprive yourself of the benefit of the
-patent license for this particular work, or (3) arrange, in a manner
-consistent with the requirements of this License, to extend the patent
-license to downstream recipients. "Knowingly relying" means you have
-actual knowledge that, but for the patent license, your conveying the
-covered work in a country, or your recipient's use of the covered work
-in a country, would infringe one or more identifiable patents in that
-country that you have reason to believe are valid.
-
- If, pursuant to or in connection with a single transaction or
-arrangement, you convey, or propagate by procuring conveyance of, a
-covered work, and grant a patent license to some of the parties
-receiving the covered work authorizing them to use, propagate, modify
-or convey a specific copy of the covered work, then the patent license
-you grant is automatically extended to all recipients of the covered
-work and works based on it.
-
- A patent license is "discriminatory" if it does not include within
-the scope of its coverage, prohibits the exercise of, or is
-conditioned on the non-exercise of one or more of the rights that are
-specifically granted under this License. You may not convey a covered
-work if you are a party to an arrangement with a third party that is
-in the business of distributing software, under which you make payment
-to the third party based on the extent of your activity of conveying
-the work, and under which the third party grants, to any of the
-parties who would receive the covered work from you, a discriminatory
-patent license (a) in connection with copies of the covered work
-conveyed by you (or copies made from those copies), or (b) primarily
-for and in connection with specific products or compilations that
-contain the covered work, unless you entered into that arrangement,
-or that patent license was granted, prior to 28 March 2007.
-
- Nothing in this License shall be construed as excluding or limiting
-any implied license or other defenses to infringement that may
-otherwise be available to you under applicable patent law.
-
- 12. No Surrender of Others' Freedom.
-
- If conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot convey a
-covered work so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you may
-not convey it at all. For example, if you agree to terms that obligate you
-to collect a royalty for further conveying from those to whom you convey
-the Program, the only way you could satisfy both those terms and this
-License would be to refrain entirely from conveying the Program.
-
- 13. Use with the GNU Affero General Public License.
-
- Notwithstanding any other provision of this License, you have
-permission to link or combine any covered work with a work licensed
-under version 3 of the GNU Affero General Public License into a single
-combined work, and to convey the resulting work. The terms of this
-License will continue to apply to the part which is the covered work,
-but the special requirements of the GNU Affero General Public License,
-section 13, concerning interaction through a network will apply to the
-combination as such.
-
- 14. Revised Versions of this License.
-
- The Free Software Foundation may publish revised and/or new versions of
-the GNU General Public License from time to time. Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
- Each version is given a distinguishing version number. If the
-Program specifies that a certain numbered version of the GNU General
-Public License "or any later version" applies to it, you have the
-option of following the terms and conditions either of that numbered
-version or of any later version published by the Free Software
-Foundation. If the Program does not specify a version number of the
-GNU General Public License, you may choose any version ever published
-by the Free Software Foundation.
-
- If the Program specifies that a proxy can decide which future
-versions of the GNU General Public License can be used, that proxy's
-public statement of acceptance of a version permanently authorizes you
-to choose that version for the Program.
-
- Later license versions may give you additional or different
-permissions. However, no additional obligations are imposed on any
-author or copyright holder as a result of your choosing to follow a
-later version.
-
- 15. Disclaimer of Warranty.
-
- THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
-APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
-HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
-OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
-THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
-IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
-ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
-
- 16. Limitation of Liability.
-
- IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
-THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
-GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
-USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
-DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
-PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
-EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGES.
-
- 17. Interpretation of Sections 15 and 16.
-
- If the disclaimer of warranty and limitation of liability provided
-above cannot be given local legal effect according to their terms,
-reviewing courts shall apply local law that most closely approximates
-an absolute waiver of all civil liability in connection with the
-Program, unless a warranty or assumption of liability accompanies a
-copy of the Program in return for a fee.
-
- END OF TERMS AND CONDITIONS
-
- How to Apply These Terms to Your New Programs
-
- If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
- To do so, attach the following notices to the program. It is safest
-to attach them to the start of each source file to most effectively
-state the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
- <one line to give the program's name and a brief idea of what it does.>
- Copyright (C) <year> <name of author>
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-Also add information on how to contact you by electronic and paper mail.
-
- If the program does terminal interaction, make it output a short
-notice like this when it starts in an interactive mode:
-
- <program> Copyright (C) <year> <name of author>
- This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
- This is free software, and you are welcome to redistribute it
- under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License. Of course, your program's commands
-might be different; for a GUI interface, you would use an "about box".
-
- You should also get your employer (if you work as a programmer) or school,
-if any, to sign a "copyright disclaimer" for the program, if necessary.
-For more information on this, and how to apply and follow the GNU GPL, see
-<http://www.gnu.org/licenses/>.
-
- The GNU General Public License does not permit incorporating your program
-into proprietary programs. If your program is a subroutine library, you
-may consider it more useful to permit linking proprietary applications with
-the library. If this is what you want to do, use the GNU Lesser General
-Public License instead of this License. But first, please read
-<http://www.gnu.org/philosophy/why-not-lgpl.html>.
-
-*/
diff --git a/packages/contracts/contracts/tokens/ZRXToken/ERC20Token_v1.sol b/packages/contracts/contracts/tokens/ZRXToken/ERC20Token_v1.sol
deleted file mode 100644
index 4920c4aac..000000000
--- a/packages/contracts/contracts/tokens/ZRXToken/ERC20Token_v1.sol
+++ /dev/null
@@ -1,44 +0,0 @@
-pragma solidity ^0.4.11;
-
-import { Token_v1 as Token } from "./Token_v1.sol";
-
-contract ERC20Token_v1 is Token {
-
- function transfer(address _to, uint _value) returns (bool) {
- //Default assumes totalSupply can't be over max (2^256 - 1).
- if (balances[msg.sender] >= _value && balances[_to] + _value >= balances[_to]) {
- balances[msg.sender] -= _value;
- balances[_to] += _value;
- Transfer(msg.sender, _to, _value);
- return true;
- } else { return false; }
- }
-
- function transferFrom(address _from, address _to, uint _value) returns (bool) {
- if (balances[_from] >= _value && allowed[_from][msg.sender] >= _value && balances[_to] + _value >= balances[_to]) {
- balances[_to] += _value;
- balances[_from] -= _value;
- allowed[_from][msg.sender] -= _value;
- Transfer(_from, _to, _value);
- return true;
- } else { return false; }
- }
-
- function balanceOf(address _owner) constant returns (uint) {
- return balances[_owner];
- }
-
- function approve(address _spender, uint _value) returns (bool) {
- allowed[msg.sender][_spender] = _value;
- Approval(msg.sender, _spender, _value);
- return true;
- }
-
- function allowance(address _owner, address _spender) constant returns (uint) {
- return allowed[_owner][_spender];
- }
-
- mapping (address => uint) balances;
- mapping (address => mapping (address => uint)) allowed;
- uint public totalSupply;
-}
diff --git a/packages/contracts/contracts/tokens/ZRXToken/Token_v1.sol b/packages/contracts/contracts/tokens/ZRXToken/Token_v1.sol
deleted file mode 100644
index de619fb7e..000000000
--- a/packages/contracts/contracts/tokens/ZRXToken/Token_v1.sol
+++ /dev/null
@@ -1,39 +0,0 @@
-pragma solidity ^0.4.11;
-
-contract Token_v1 {
-
- /// @return total amount of tokens
- function totalSupply() constant returns (uint supply) {}
-
- /// @param _owner The address from which the balance will be retrieved
- /// @return The balance
- function balanceOf(address _owner) constant returns (uint balance) {}
-
- /// @notice send `_value` token to `_to` from `msg.sender`
- /// @param _to The address of the recipient
- /// @param _value The amount of token to be transferred
- /// @return Whether the transfer was successful or not
- function transfer(address _to, uint _value) returns (bool success) {}
-
- /// @notice send `_value` token to `_to` from `_from` on the condition it is approved by `_from`
- /// @param _from The address of the sender
- /// @param _to The address of the recipient
- /// @param _value The amount of token to be transferred
- /// @return Whether the transfer was successful or not
- function transferFrom(address _from, address _to, uint _value) returns (bool success) {}
-
- /// @notice `msg.sender` approves `_addr` to spend `_value` tokens
- /// @param _spender The address of the account able to transfer the tokens
- /// @param _value The amount of wei to be approved for transfer
- /// @return Whether the approval was successful or not
- function approve(address _spender, uint _value) returns (bool success) {}
-
- /// @param _owner The address of the account owning tokens
- /// @param _spender The address of the account able to transfer the tokens
- /// @return Amount of remaining tokens allowed to spent
- function allowance(address _owner, address _spender) constant returns (uint remaining) {}
-
- event Transfer(address indexed _from, address indexed _to, uint _value);
- event Approval(address indexed _owner, address indexed _spender, uint _value);
-}
-
diff --git a/packages/contracts/contracts/tokens/ZRXToken/UnlimitedAllowanceToken_v1.sol b/packages/contracts/contracts/tokens/ZRXToken/UnlimitedAllowanceToken_v1.sol
deleted file mode 100644
index bf1b0335a..000000000
--- a/packages/contracts/contracts/tokens/ZRXToken/UnlimitedAllowanceToken_v1.sol
+++ /dev/null
@@ -1,52 +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.11;
-
-import { ERC20Token_v1 as ERC20Token } from "./ERC20Token_v1.sol";
-
-contract UnlimitedAllowanceToken_v1 is ERC20Token {
-
- uint constant MAX_UINT = 2**256 - 1;
-
- /// @dev ERC20 transferFrom, modified such that an allowance of MAX_UINT represents an unlimited allowance.
- /// @param _from Address to transfer from.
- /// @param _to Address to transfer to.
- /// @param _value Amount to transfer.
- /// @return Success of transfer.
- function transferFrom(address _from, address _to, uint _value)
- public
- returns (bool)
- {
- uint allowance = allowed[_from][msg.sender];
- if (balances[_from] >= _value
- && allowance >= _value
- && balances[_to] + _value >= balances[_to]
- ) {
- balances[_to] += _value;
- balances[_from] -= _value;
- if (allowance < MAX_UINT) {
- allowed[_from][msg.sender] -= _value;
- }
- Transfer(_from, _to, _value);
- return true;
- } else {
- return false;
- }
- }
-}
diff --git a/packages/contracts/contracts/tokens/ZRXToken/ZRXToken.sol b/packages/contracts/contracts/tokens/ZRXToken/ZRXToken.sol
deleted file mode 100644
index 831e1822c..000000000
--- a/packages/contracts/contracts/tokens/ZRXToken/ZRXToken.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.11;
-
-// solhint-disable-next-line max-line-length
-import { UnlimitedAllowanceToken_v1 as UnlimitedAllowanceToken } from "./UnlimitedAllowanceToken_v1.sol";
-
-
-contract ZRXToken is
- UnlimitedAllowanceToken
-{
-
- // solhint-disable const-name-snakecase
- uint8 constant public decimals = 18;
- uint256 public totalSupply = 10**27; // 1 billion tokens, 18 decimal places
- string constant public name = "0x Protocol Token";
- string constant public symbol = "ZRX";
- // solhint-enableconst-name-snakecase
-
- function ZRXToken()
- public
- {
- balances[msg.sender] = totalSupply;
- }
-}
diff --git a/packages/contracts/contracts/utils/LibBytes/LibBytes.sol b/packages/contracts/contracts/utils/LibBytes/LibBytes.sol
deleted file mode 100644
index 369f588ad..000000000
--- a/packages/contracts/contracts/utils/LibBytes/LibBytes.sol
+++ /dev/null
@@ -1,567 +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;
-
-
-library LibBytes {
-
- using LibBytes for bytes;
-
- /// @dev Gets the memory address for a byte array.
- /// @param input Byte array to lookup.
- /// @return memoryAddress Memory address of byte array. This
- /// points to the header of the byte array which contains
- /// the length.
- function rawAddress(bytes memory input)
- internal
- pure
- returns (uint256 memoryAddress)
- {
- assembly {
- memoryAddress := input
- }
- return memoryAddress;
- }
-
- /// @dev Gets the memory address for the contents of a byte array.
- /// @param input Byte array to lookup.
- /// @return memoryAddress Memory address of the contents of the byte array.
- function contentAddress(bytes memory input)
- internal
- pure
- returns (uint256 memoryAddress)
- {
- assembly {
- memoryAddress := add(input, 32)
- }
- return memoryAddress;
- }
-
- /// @dev Copies `length` bytes from memory location `source` to `dest`.
- /// @param dest memory address to copy bytes to.
- /// @param source memory address to copy bytes from.
- /// @param length number of bytes to copy.
- function memCopy(
- uint256 dest,
- uint256 source,
- uint256 length
- )
- internal
- pure
- {
- if (length < 32) {
- // Handle a partial word by reading destination and masking
- // off the bits we are interested in.
- // This correctly handles overlap, zero lengths and source == dest
- assembly {
- let mask := sub(exp(256, sub(32, length)), 1)
- let s := and(mload(source), not(mask))
- let d := and(mload(dest), mask)
- mstore(dest, or(s, d))
- }
- } else {
- // Skip the O(length) loop when source == dest.
- if (source == dest) {
- return;
- }
-
- // For large copies we copy whole words at a time. The final
- // word is aligned to the end of the range (instead of after the
- // previous) to handle partial words. So a copy will look like this:
- //
- // ####
- // ####
- // ####
- // ####
- //
- // We handle overlap in the source and destination range by
- // changing the copying direction. This prevents us from
- // overwriting parts of source that we still need to copy.
- //
- // This correctly handles source == dest
- //
- if (source > dest) {
- assembly {
- // We subtract 32 from `sEnd` and `dEnd` because it
- // is easier to compare with in the loop, and these
- // are also the addresses we need for copying the
- // last bytes.
- length := sub(length, 32)
- let sEnd := add(source, length)
- let dEnd := add(dest, length)
-
- // Remember the last 32 bytes of source
- // This needs to be done here and not after the loop
- // because we may have overwritten the last bytes in
- // source already due to overlap.
- let last := mload(sEnd)
-
- // Copy whole words front to back
- // Note: the first check is always true,
- // this could have been a do-while loop.
- // solhint-disable-next-line no-empty-blocks
- for {} lt(source, sEnd) {} {
- mstore(dest, mload(source))
- source := add(source, 32)
- dest := add(dest, 32)
- }
-
- // Write the last 32 bytes
- mstore(dEnd, last)
- }
- } else {
- assembly {
- // We subtract 32 from `sEnd` and `dEnd` because those
- // are the starting points when copying a word at the end.
- length := sub(length, 32)
- let sEnd := add(source, length)
- let dEnd := add(dest, length)
-
- // Remember the first 32 bytes of source
- // This needs to be done here and not after the loop
- // because we may have overwritten the first bytes in
- // source already due to overlap.
- let first := mload(source)
-
- // Copy whole words back to front
- // We use a signed comparisson here to allow dEnd to become
- // negative (happens when source and dest < 32). Valid
- // addresses in local memory will never be larger than
- // 2**255, so they can be safely re-interpreted as signed.
- // Note: the first check is always true,
- // this could have been a do-while loop.
- // solhint-disable-next-line no-empty-blocks
- for {} slt(dest, dEnd) {} {
- mstore(dEnd, mload(sEnd))
- sEnd := sub(sEnd, 32)
- dEnd := sub(dEnd, 32)
- }
-
- // Write the first 32 bytes
- mstore(dest, first)
- }
- }
- }
- }
-
- /// @dev Returns a slices from a byte array.
- /// @param b The byte array to take a slice from.
- /// @param from The starting index for the slice (inclusive).
- /// @param to The final index for the slice (exclusive).
- /// @return result The slice containing bytes at indices [from, to)
- function slice(
- bytes memory b,
- uint256 from,
- uint256 to
- )
- internal
- pure
- returns (bytes memory result)
- {
- require(
- from <= to,
- "FROM_LESS_THAN_TO_REQUIRED"
- );
- require(
- to < b.length,
- "TO_LESS_THAN_LENGTH_REQUIRED"
- );
-
- // Create a new bytes structure and copy contents
- result = new bytes(to - from);
- memCopy(
- result.contentAddress(),
- b.contentAddress() + from,
- result.length
- );
- return result;
- }
-
- /// @dev Returns a slice from a byte array without preserving the input.
- /// @param b The byte array to take a slice from. Will be destroyed in the process.
- /// @param from The starting index for the slice (inclusive).
- /// @param to The final index for the slice (exclusive).
- /// @return result The slice containing bytes at indices [from, to)
- /// @dev When `from == 0`, the original array will match the slice. In other cases its state will be corrupted.
- function sliceDestructive(
- bytes memory b,
- uint256 from,
- uint256 to
- )
- internal
- pure
- returns (bytes memory result)
- {
- require(
- from <= to,
- "FROM_LESS_THAN_TO_REQUIRED"
- );
- require(
- to < b.length,
- "TO_LESS_THAN_LENGTH_REQUIRED"
- );
-
- // Create a new bytes structure around [from, to) in-place.
- assembly {
- result := add(b, from)
- mstore(result, sub(to, from))
- }
- return result;
- }
-
- /// @dev Pops the last byte off of a byte array by modifying its length.
- /// @param b Byte array that will be modified.
- /// @return The byte that was popped off.
- function popLastByte(bytes memory b)
- internal
- pure
- returns (bytes1 result)
- {
- require(
- b.length > 0,
- "GREATER_THAN_ZERO_LENGTH_REQUIRED"
- );
-
- // Store last byte.
- result = b[b.length - 1];
-
- assembly {
- // Decrement length of byte array.
- let newLen := sub(mload(b), 1)
- mstore(b, newLen)
- }
- return result;
- }
-
- /// @dev Pops the last 20 bytes off of a byte array by modifying its length.
- /// @param b Byte array that will be modified.
- /// @return The 20 byte address that was popped off.
- function popLast20Bytes(bytes memory b)
- internal
- pure
- returns (address result)
- {
- require(
- b.length >= 20,
- "GREATER_OR_EQUAL_TO_20_LENGTH_REQUIRED"
- );
-
- // Store last 20 bytes.
- result = readAddress(b, b.length - 20);
-
- assembly {
- // Subtract 20 from byte array length.
- let newLen := sub(mload(b), 20)
- mstore(b, newLen)
- }
- return result;
- }
-
- /// @dev Tests equality of two byte arrays.
- /// @param lhs First byte array to compare.
- /// @param rhs Second byte array to compare.
- /// @return True if arrays are the same. False otherwise.
- function equals(
- bytes memory lhs,
- bytes memory rhs
- )
- internal
- pure
- returns (bool equal)
- {
- // Keccak gas cost is 30 + numWords * 6. This is a cheap way to compare.
- // We early exit on unequal lengths, but keccak would also correctly
- // handle this.
- return lhs.length == rhs.length && keccak256(lhs) == keccak256(rhs);
- }
-
- /// @dev Reads an address from a position in a byte array.
- /// @param b Byte array containing an address.
- /// @param index Index in byte array of address.
- /// @return address from byte array.
- function readAddress(
- bytes memory b,
- uint256 index
- )
- internal
- pure
- returns (address result)
- {
- require(
- b.length >= index + 20, // 20 is length of address
- "GREATER_OR_EQUAL_TO_20_LENGTH_REQUIRED"
- );
-
- // Add offset to index:
- // 1. Arrays are prefixed by 32-byte length parameter (add 32 to index)
- // 2. Account for size difference between address length and 32-byte storage word (subtract 12 from index)
- index += 20;
-
- // Read address from array memory
- assembly {
- // 1. Add index to address of bytes array
- // 2. Load 32-byte word from memory
- // 3. Apply 20-byte mask to obtain address
- result := and(mload(add(b, index)), 0xffffffffffffffffffffffffffffffffffffffff)
- }
- return result;
- }
-
- /// @dev Writes an address into a specific position in a byte array.
- /// @param b Byte array to insert address into.
- /// @param index Index in byte array of address.
- /// @param input Address to put into byte array.
- function writeAddress(
- bytes memory b,
- uint256 index,
- address input
- )
- internal
- pure
- {
- require(
- b.length >= index + 20, // 20 is length of address
- "GREATER_OR_EQUAL_TO_20_LENGTH_REQUIRED"
- );
-
- // Add offset to index:
- // 1. Arrays are prefixed by 32-byte length parameter (add 32 to index)
- // 2. Account for size difference between address length and 32-byte storage word (subtract 12 from index)
- index += 20;
-
- // Store address into array memory
- assembly {
- // The address occupies 20 bytes and mstore stores 32 bytes.
- // First fetch the 32-byte word where we'll be storing the address, then
- // apply a mask so we have only the bytes in the word that the address will not occupy.
- // Then combine these bytes with the address and store the 32 bytes back to memory with mstore.
-
- // 1. Add index to address of bytes array
- // 2. Load 32-byte word from memory
- // 3. Apply 12-byte mask to obtain extra bytes occupying word of memory where we'll store the address
- let neighbors := and(
- mload(add(b, index)),
- 0xffffffffffffffffffffffff0000000000000000000000000000000000000000
- )
-
- // Make sure input address is clean.
- // (Solidity does not guarantee this)
- input := and(input, 0xffffffffffffffffffffffffffffffffffffffff)
-
- // Store the neighbors and address into memory
- mstore(add(b, index), xor(input, neighbors))
- }
- }
-
- /// @dev Reads a bytes32 value from a position in a byte array.
- /// @param b Byte array containing a bytes32 value.
- /// @param index Index in byte array of bytes32 value.
- /// @return bytes32 value from byte array.
- function readBytes32(
- bytes memory b,
- uint256 index
- )
- internal
- pure
- returns (bytes32 result)
- {
- require(
- b.length >= index + 32,
- "GREATER_OR_EQUAL_TO_32_LENGTH_REQUIRED"
- );
-
- // Arrays are prefixed by a 256 bit length parameter
- index += 32;
-
- // Read the bytes32 from array memory
- assembly {
- result := mload(add(b, index))
- }
- return result;
- }
-
- /// @dev Writes a bytes32 into a specific position in a byte array.
- /// @param b Byte array to insert <input> into.
- /// @param index Index in byte array of <input>.
- /// @param input bytes32 to put into byte array.
- function writeBytes32(
- bytes memory b,
- uint256 index,
- bytes32 input
- )
- internal
- pure
- {
- require(
- b.length >= index + 32,
- "GREATER_OR_EQUAL_TO_32_LENGTH_REQUIRED"
- );
-
- // Arrays are prefixed by a 256 bit length parameter
- index += 32;
-
- // Read the bytes32 from array memory
- assembly {
- mstore(add(b, index), input)
- }
- }
-
- /// @dev Reads a uint256 value from a position in a byte array.
- /// @param b Byte array containing a uint256 value.
- /// @param index Index in byte array of uint256 value.
- /// @return uint256 value from byte array.
- function readUint256(
- bytes memory b,
- uint256 index
- )
- internal
- pure
- returns (uint256 result)
- {
- result = uint256(readBytes32(b, index));
- return result;
- }
-
- /// @dev Writes a uint256 into a specific position in a byte array.
- /// @param b Byte array to insert <input> into.
- /// @param index Index in byte array of <input>.
- /// @param input uint256 to put into byte array.
- function writeUint256(
- bytes memory b,
- uint256 index,
- uint256 input
- )
- internal
- pure
- {
- writeBytes32(b, index, bytes32(input));
- }
-
- /// @dev Reads an unpadded bytes4 value from a position in a byte array.
- /// @param b Byte array containing a bytes4 value.
- /// @param index Index in byte array of bytes4 value.
- /// @return bytes4 value from byte array.
- function readBytes4(
- bytes memory b,
- uint256 index
- )
- internal
- pure
- returns (bytes4 result)
- {
- require(
- b.length >= index + 4,
- "GREATER_OR_EQUAL_TO_4_LENGTH_REQUIRED"
- );
-
- // Arrays are prefixed by a 32 byte length field
- index += 32;
-
- // Read the bytes4 from array memory
- assembly {
- result := mload(add(b, index))
- // Solidity does not require us to clean the trailing bytes.
- // We do it anyway
- result := and(result, 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000)
- }
- return result;
- }
-
- /// @dev Reads nested bytes from a specific position.
- /// @dev NOTE: the returned value overlaps with the input value.
- /// Both should be treated as immutable.
- /// @param b Byte array containing nested bytes.
- /// @param index Index of nested bytes.
- /// @return result Nested bytes.
- function readBytesWithLength(
- bytes memory b,
- uint256 index
- )
- internal
- pure
- returns (bytes memory result)
- {
- // Read length of nested bytes
- uint256 nestedBytesLength = readUint256(b, index);
- index += 32;
-
- // Assert length of <b> is valid, given
- // length of nested bytes
- require(
- b.length >= index + nestedBytesLength,
- "GREATER_OR_EQUAL_TO_NESTED_BYTES_LENGTH_REQUIRED"
- );
-
- // Return a pointer to the byte array as it exists inside `b`
- assembly {
- result := add(b, index)
- }
- return result;
- }
-
- /// @dev Inserts bytes at a specific position in a byte array.
- /// @param b Byte array to insert <input> into.
- /// @param index Index in byte array of <input>.
- /// @param input bytes to insert.
- function writeBytesWithLength(
- bytes memory b,
- uint256 index,
- bytes memory input
- )
- internal
- pure
- {
- // Assert length of <b> is valid, given
- // length of input
- require(
- b.length >= index + 32 + input.length, // 32 bytes to store length
- "GREATER_OR_EQUAL_TO_NESTED_BYTES_LENGTH_REQUIRED"
- );
-
- // Copy <input> into <b>
- memCopy(
- b.contentAddress() + index,
- input.rawAddress(), // includes length of <input>
- input.length + 32 // +32 bytes to store <input> length
- );
- }
-
- /// @dev Performs a deep copy of a byte array onto another byte array of greater than or equal length.
- /// @param dest Byte array that will be overwritten with source bytes.
- /// @param source Byte array to copy onto dest bytes.
- function deepCopyBytes(
- bytes memory dest,
- bytes memory source
- )
- internal
- pure
- {
- uint256 sourceLen = source.length;
- // Dest length must be >= source length, or some bytes would not be copied.
- require(
- dest.length >= sourceLen,
- "GREATER_OR_EQUAL_TO_SOURCE_BYTES_LENGTH_REQUIRED"
- );
- memCopy(
- dest.contentAddress(),
- source.contentAddress(),
- sourceLen
- );
- }
-}
diff --git a/packages/contracts/contracts/utils/Ownable/IOwnable.sol b/packages/contracts/contracts/utils/Ownable/IOwnable.sol
deleted file mode 100644
index 5deb13497..000000000
--- a/packages/contracts/contracts/utils/Ownable/IOwnable.sol
+++ /dev/null
@@ -1,8 +0,0 @@
-pragma solidity 0.4.24;
-
-
-contract IOwnable {
-
- function transferOwnership(address newOwner)
- public;
-}
diff --git a/packages/contracts/contracts/utils/Ownable/Ownable.sol b/packages/contracts/contracts/utils/Ownable/Ownable.sol
deleted file mode 100644
index 0c830be68..000000000
--- a/packages/contracts/contracts/utils/Ownable/Ownable.sol
+++ /dev/null
@@ -1,33 +0,0 @@
-pragma solidity 0.4.24;
-
-import "./IOwnable.sol";
-
-
-contract Ownable is
- IOwnable
-{
- address public owner;
-
- constructor ()
- public
- {
- owner = msg.sender;
- }
-
- modifier onlyOwner() {
- require(
- msg.sender == owner,
- "ONLY_CONTRACT_OWNER"
- );
- _;
- }
-
- function transferOwnership(address newOwner)
- public
- onlyOwner
- {
- if (newOwner != address(0)) {
- owner = newOwner;
- }
- }
-}
diff --git a/packages/contracts/contracts/utils/ReentrancyGuard/ReentrancyGuard.sol b/packages/contracts/contracts/utils/ReentrancyGuard/ReentrancyGuard.sol
deleted file mode 100644
index 9f98a7a16..000000000
--- a/packages/contracts/contracts/utils/ReentrancyGuard/ReentrancyGuard.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;
-
-
-contract ReentrancyGuard {
-
- // Locked state of mutex
- bool private locked = false;
-
- /// @dev Functions with this modifer cannot be reentered. The mutex will be locked
- /// before function execution and unlocked after.
- modifier nonReentrant() {
- // Ensure mutex is unlocked
- require(
- !locked,
- "REENTRANCY_ILLEGAL"
- );
-
- // Lock mutex before function call
- locked = true;
-
- // Perform function call
- _;
-
- // Unlock mutex after function call
- locked = false;
- }
-}
diff --git a/packages/contracts/contracts/utils/SafeMath/SafeMath.sol b/packages/contracts/contracts/utils/SafeMath/SafeMath.sol
deleted file mode 100644
index 2855edb9d..000000000
--- a/packages/contracts/contracts/utils/SafeMath/SafeMath.sol
+++ /dev/null
@@ -1,87 +0,0 @@
-pragma solidity 0.4.24;
-
-
-contract SafeMath {
-
- function safeMul(uint256 a, uint256 b)
- internal
- pure
- returns (uint256)
- {
- if (a == 0) {
- return 0;
- }
- uint256 c = a * b;
- require(
- c / a == b,
- "UINT256_OVERFLOW"
- );
- return c;
- }
-
- function safeDiv(uint256 a, uint256 b)
- internal
- pure
- returns (uint256)
- {
- uint256 c = a / b;
- return c;
- }
-
- function safeSub(uint256 a, uint256 b)
- internal
- pure
- returns (uint256)
- {
- require(
- b <= a,
- "UINT256_UNDERFLOW"
- );
- return a - b;
- }
-
- function safeAdd(uint256 a, uint256 b)
- internal
- pure
- returns (uint256)
- {
- uint256 c = a + b;
- require(
- c >= a,
- "UINT256_OVERFLOW"
- );
- return c;
- }
-
- function max64(uint64 a, uint64 b)
- internal
- pure
- returns (uint256)
- {
- return a >= b ? a : b;
- }
-
- function min64(uint64 a, uint64 b)
- internal
- pure
- returns (uint256)
- {
- return a < b ? a : b;
- }
-
- function max256(uint256 a, uint256 b)
- internal
- pure
- returns (uint256)
- {
- return a >= b ? a : b;
- }
-
- function min256(uint256 a, uint256 b)
- internal
- pure
- returns (uint256)
- {
- return a < b ? a : b;
- }
-}
diff --git a/packages/contracts/package.json b/packages/contracts/package.json
deleted file mode 100644
index 16dd3c9c1..000000000
--- a/packages/contracts/package.json
+++ /dev/null
@@ -1,94 +0,0 @@
-{
- "private": true,
- "name": "contracts",
- "version": "2.1.56",
- "engines": {
- "node": ">=6.12"
- },
- "description": "Smart contract components 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 --contracts-dir contracts",
- "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 contracts/**/**/**/**/*.sol"
- },
- "config": {
- "abis":
- "generated-artifacts/@(AssetProxyOwner|DummyERC20Token|DummyERC721Receiver|DummyERC721Token|DummyMultipleReturnERC20Token|DummyNoReturnERC20Token|ERC20Token|ERC20Proxy|ERC721Token|ERC721Proxy|Forwarder|Exchange|ExchangeWrapper|IAssetData|IAssetProxy|InvalidERC721Receiver|MixinAuthorizable|MultiAssetProxy|MultiSigWallet|MultiSigWalletWithTimeLock|OrderValidator|ReentrantERC20Token|TestAssetProxyOwner|TestAssetProxyDispatcher|TestConstants|TestExchangeInternals|TestLibBytes|TestLibs|TestSignatureValidator|TestStaticCallReceiver|Validator|Wallet|Whitelist|WETH9|ZRXToken).json"
- },
- "repository": {
- "type": "git",
- "url": "https://github.com/0xProject/0x-monorepo.git"
- },
- "author": "Amir Bandeali",
- "license": "Apache-2.0",
- "bugs": {
- "url": "https://github.com/0xProject/0x-monorepo/issues"
- },
- "homepage": "https://github.com/0xProject/0x-monorepo/packages/contracts/README.md",
- "devDependencies": {
- "@0x/abi-gen": "^1.0.17",
- "@0x/dev-utils": "^1.0.19",
- "@0x/sol-compiler": "^1.1.14",
- "@0x/sol-cov": "^2.1.14",
- "@0x/subproviders": "^2.1.6",
- "@0x/tslint-config": "^1.0.10",
- "@types/bn.js": "^4.11.0",
- "@types/ethereumjs-abi": "^0.6.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": "^2.0.1",
- "dirty-chai": "^2.0.1",
- "make-promises-safe": "^1.1.0",
- "mocha": "^4.1.0",
- "npm-run-all": "^4.1.2",
- "shx": "^0.2.2",
- "solc": "^0.4.24",
- "solhint": "^1.2.1",
- "tslint": "5.11.0",
- "typescript": "3.0.1",
- "yargs": "^10.0.3"
- },
- "dependencies": {
- "@0x/base-contract": "^3.0.8",
- "@0x/order-utils": "^3.0.4",
- "@0x/types": "^1.3.0",
- "@0x/typescript-typings": "^3.0.4",
- "@0x/utils": "^2.0.6",
- "@0x/web3-wrapper": "^3.1.6",
- "@types/js-combinatorics": "^0.5.29",
- "bn.js": "^4.11.8",
- "ethereum-types": "^1.1.2",
- "ethereumjs-abi": "0.6.5",
- "ethereumjs-util": "^5.1.1",
- "ethers": "~4.0.4",
- "js-combinatorics": "^0.5.3",
- "lodash": "^4.17.5"
- },
- "publishConfig": {
- "access": "public"
- }
-}
diff --git a/packages/contracts/src/artifacts/index.ts b/packages/contracts/src/artifacts/index.ts
deleted file mode 100644
index 97c1b6209..000000000
--- a/packages/contracts/src/artifacts/index.ts
+++ /dev/null
@@ -1,81 +0,0 @@
-import { ContractArtifact } from 'ethereum-types';
-
-import * as AssetProxyOwner from '../../generated-artifacts/AssetProxyOwner.json';
-import * as DummyERC20Token from '../../generated-artifacts/DummyERC20Token.json';
-import * as DummyERC721Receiver from '../../generated-artifacts/DummyERC721Receiver.json';
-import * as DummyERC721Token from '../../generated-artifacts/DummyERC721Token.json';
-import * as DummyMultipleReturnERC20Token from '../../generated-artifacts/DummyMultipleReturnERC20Token.json';
-import * as DummyNoReturnERC20Token from '../../generated-artifacts/DummyNoReturnERC20Token.json';
-import * as ERC20Proxy from '../../generated-artifacts/ERC20Proxy.json';
-import * as ERC20Token from '../../generated-artifacts/ERC20Token.json';
-import * as ERC721Proxy from '../../generated-artifacts/ERC721Proxy.json';
-import * as ERC721Token from '../../generated-artifacts/ERC721Token.json';
-import * as Exchange from '../../generated-artifacts/Exchange.json';
-import * as ExchangeWrapper from '../../generated-artifacts/ExchangeWrapper.json';
-import * as Forwarder from '../../generated-artifacts/Forwarder.json';
-import * as IAssetData from '../../generated-artifacts/IAssetData.json';
-import * as IAssetProxy from '../../generated-artifacts/IAssetProxy.json';
-import * as InvalidERC721Receiver from '../../generated-artifacts/InvalidERC721Receiver.json';
-import * as IValidator from '../../generated-artifacts/IValidator.json';
-import * as IWallet from '../../generated-artifacts/IWallet.json';
-import * as MixinAuthorizable from '../../generated-artifacts/MixinAuthorizable.json';
-import * as MultiAssetProxy from '../../generated-artifacts/MultiAssetProxy.json';
-import * as MultiSigWallet from '../../generated-artifacts/MultiSigWallet.json';
-import * as MultiSigWalletWithTimeLock from '../../generated-artifacts/MultiSigWalletWithTimeLock.json';
-import * as OrderValidator from '../../generated-artifacts/OrderValidator.json';
-import * as ReentrantERC20Token from '../../generated-artifacts/ReentrantERC20Token.json';
-import * as TestAssetProxyDispatcher from '../../generated-artifacts/TestAssetProxyDispatcher.json';
-import * as TestAssetProxyOwner from '../../generated-artifacts/TestAssetProxyOwner.json';
-import * as TestConstants from '../../generated-artifacts/TestConstants.json';
-import * as TestExchangeInternals from '../../generated-artifacts/TestExchangeInternals.json';
-import * as TestLibBytes from '../../generated-artifacts/TestLibBytes.json';
-import * as TestLibs from '../../generated-artifacts/TestLibs.json';
-import * as TestSignatureValidator from '../../generated-artifacts/TestSignatureValidator.json';
-import * as TestStaticCallReceiver from '../../generated-artifacts/TestStaticCallReceiver.json';
-import * as Validator from '../../generated-artifacts/Validator.json';
-import * as Wallet from '../../generated-artifacts/Wallet.json';
-import * as WETH9 from '../../generated-artifacts/WETH9.json';
-import * as Whitelist from '../../generated-artifacts/Whitelist.json';
-import * as ZRXToken from '../../generated-artifacts/ZRXToken.json';
-
-export const artifacts = {
- AssetProxyOwner: AssetProxyOwner as ContractArtifact,
- DummyERC20Token: DummyERC20Token as ContractArtifact,
- DummyERC721Receiver: DummyERC721Receiver as ContractArtifact,
- DummyERC721Token: DummyERC721Token as ContractArtifact,
- DummyMultipleReturnERC20Token: DummyMultipleReturnERC20Token as ContractArtifact,
- DummyNoReturnERC20Token: DummyNoReturnERC20Token as ContractArtifact,
- ERC20Proxy: ERC20Proxy as ContractArtifact,
- ERC20Token: ERC20Token as ContractArtifact,
- ERC721Proxy: ERC721Proxy as ContractArtifact,
- ERC721Token: ERC721Token as ContractArtifact,
- Exchange: Exchange as ContractArtifact,
- ExchangeWrapper: ExchangeWrapper as ContractArtifact,
- Forwarder: Forwarder as ContractArtifact,
- IAssetData: IAssetData as ContractArtifact,
- IAssetProxy: IAssetProxy as ContractArtifact,
- IValidator: IValidator as ContractArtifact,
- IWallet: IWallet as ContractArtifact,
- InvalidERC721Receiver: InvalidERC721Receiver as ContractArtifact,
- MixinAuthorizable: MixinAuthorizable as ContractArtifact,
- MultiAssetProxy: MultiAssetProxy as ContractArtifact,
- MultiSigWallet: MultiSigWallet as ContractArtifact,
- MultiSigWalletWithTimeLock: MultiSigWalletWithTimeLock as ContractArtifact,
- OrderValidator: OrderValidator as ContractArtifact,
- ReentrantERC20Token: ReentrantERC20Token as ContractArtifact,
- TestAssetProxyDispatcher: TestAssetProxyDispatcher as ContractArtifact,
- TestAssetProxyOwner: TestAssetProxyOwner as ContractArtifact,
- TestConstants: TestConstants as ContractArtifact,
- TestExchangeInternals: TestExchangeInternals as ContractArtifact,
- TestLibBytes: TestLibBytes as ContractArtifact,
- TestLibs: TestLibs as ContractArtifact,
- TestSignatureValidator: TestSignatureValidator as ContractArtifact,
- TestStaticCallReceiver: TestStaticCallReceiver as ContractArtifact,
- Validator: Validator as ContractArtifact,
- WETH9: WETH9 as ContractArtifact,
- Wallet: Wallet as ContractArtifact,
- Whitelist: Whitelist as ContractArtifact,
- // Note(albrow): "as any" hack still required here because ZRXToken does not
- // conform to the v2 artifact type.
- ZRXToken: (ZRXToken as any) as ContractArtifact,
-};
diff --git a/packages/contracts/src/wrappers/index.ts b/packages/contracts/src/wrappers/index.ts
deleted file mode 100644
index 9ca676b56..000000000
--- a/packages/contracts/src/wrappers/index.ts
+++ /dev/null
@@ -1,34 +0,0 @@
-export * from '../../generated-wrappers/asset_proxy_owner';
-export * from '../../generated-wrappers/dummy_erc20_token';
-export * from '../../generated-wrappers/dummy_erc721_receiver';
-export * from '../../generated-wrappers/dummy_erc721_token';
-export * from '../../generated-wrappers/dummy_multiple_return_erc20_token';
-export * from '../../generated-wrappers/dummy_no_return_erc20_token';
-export * from '../../generated-wrappers/erc20_proxy';
-export * from '../../generated-wrappers/erc721_proxy';
-export * from '../../generated-wrappers/erc20_token';
-export * from '../../generated-wrappers/erc721_token';
-export * from '../../generated-wrappers/exchange';
-export * from '../../generated-wrappers/exchange_wrapper';
-export * from '../../generated-wrappers/forwarder';
-export * from '../../generated-wrappers/i_asset_data';
-export * from '../../generated-wrappers/i_asset_proxy';
-export * from '../../generated-wrappers/invalid_erc721_receiver';
-export * from '../../generated-wrappers/mixin_authorizable';
-export * from '../../generated-wrappers/multi_sig_wallet';
-export * from '../../generated-wrappers/multi_sig_wallet_with_time_lock';
-export * from '../../generated-wrappers/order_validator';
-export * from '../../generated-wrappers/reentrant_erc20_token';
-export * from '../../generated-wrappers/test_asset_proxy_dispatcher';
-export * from '../../generated-wrappers/test_asset_proxy_owner';
-export * from '../../generated-wrappers/test_constants';
-export * from '../../generated-wrappers/test_exchange_internals';
-export * from '../../generated-wrappers/test_lib_bytes';
-export * from '../../generated-wrappers/test_libs';
-export * from '../../generated-wrappers/test_signature_validator';
-export * from '../../generated-wrappers/test_static_call_receiver';
-export * from '../../generated-wrappers/validator';
-export * from '../../generated-wrappers/wallet';
-export * from '../../generated-wrappers/weth9';
-export * from '../../generated-wrappers/whitelist';
-export * from '../../generated-wrappers/zrx_token';
diff --git a/packages/contracts/test/asset_proxy/authorizable.ts b/packages/contracts/test/asset_proxy/authorizable.ts
deleted file mode 100644
index e21af9b81..000000000
--- a/packages/contracts/test/asset_proxy/authorizable.ts
+++ /dev/null
@@ -1,207 +0,0 @@
-import { BlockchainLifecycle } from '@0x/dev-utils';
-import { RevertReason } from '@0x/types';
-import { BigNumber } from '@0x/utils';
-import * as chai from 'chai';
-import * as _ from 'lodash';
-
-import { MixinAuthorizableContract } from '../../generated-wrappers/mixin_authorizable';
-import { artifacts } from '../../src/artifacts';
-import { expectTransactionFailedAsync } from '../utils/assertions';
-import { chaiSetup } from '../utils/chai_setup';
-import { constants } from '../utils/constants';
-import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper';
-
-chaiSetup.configure();
-const expect = chai.expect;
-const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
-
-describe('Authorizable', () => {
- let owner: string;
- let notOwner: string;
- let address: string;
- let authorizable: MixinAuthorizableContract;
-
- before(async () => {
- await blockchainLifecycle.startAsync();
- });
- after(async () => {
- await blockchainLifecycle.revertAsync();
- });
- before(async () => {
- const accounts = await web3Wrapper.getAvailableAddressesAsync();
- [owner, address, notOwner] = _.slice(accounts, 0, 3);
- authorizable = await MixinAuthorizableContract.deployFrom0xArtifactAsync(
- artifacts.MixinAuthorizable,
- provider,
- txDefaults,
- );
- });
- beforeEach(async () => {
- await blockchainLifecycle.startAsync();
- });
- afterEach(async () => {
- await blockchainLifecycle.revertAsync();
- });
- describe('addAuthorizedAddress', () => {
- it('should throw if not called by owner', async () => {
- return expectTransactionFailedAsync(
- authorizable.addAuthorizedAddress.sendTransactionAsync(notOwner, { from: notOwner }),
- RevertReason.OnlyContractOwner,
- );
- });
- it('should allow owner to add an authorized address', async () => {
- await web3Wrapper.awaitTransactionSuccessAsync(
- await authorizable.addAuthorizedAddress.sendTransactionAsync(address, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const isAuthorized = await authorizable.authorized.callAsync(address);
- expect(isAuthorized).to.be.true();
- });
- it('should throw if owner attempts to authorize a duplicate address', async () => {
- await web3Wrapper.awaitTransactionSuccessAsync(
- await authorizable.addAuthorizedAddress.sendTransactionAsync(address, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- return expectTransactionFailedAsync(
- authorizable.addAuthorizedAddress.sendTransactionAsync(address, { from: owner }),
- RevertReason.TargetAlreadyAuthorized,
- );
- });
- });
-
- describe('removeAuthorizedAddress', () => {
- it('should throw if not called by owner', async () => {
- await web3Wrapper.awaitTransactionSuccessAsync(
- await authorizable.addAuthorizedAddress.sendTransactionAsync(address, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- return expectTransactionFailedAsync(
- authorizable.removeAuthorizedAddress.sendTransactionAsync(address, {
- from: notOwner,
- }),
- RevertReason.OnlyContractOwner,
- );
- });
-
- it('should allow owner to remove an authorized address', async () => {
- await web3Wrapper.awaitTransactionSuccessAsync(
- await authorizable.addAuthorizedAddress.sendTransactionAsync(address, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await authorizable.removeAuthorizedAddress.sendTransactionAsync(address, {
- from: owner,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const isAuthorized = await authorizable.authorized.callAsync(address);
- expect(isAuthorized).to.be.false();
- });
-
- it('should throw if owner attempts to remove an address that is not authorized', async () => {
- return expectTransactionFailedAsync(
- authorizable.removeAuthorizedAddress.sendTransactionAsync(address, {
- from: owner,
- }),
- RevertReason.TargetNotAuthorized,
- );
- });
- });
-
- describe('removeAuthorizedAddressAtIndex', () => {
- it('should throw if not called by owner', async () => {
- await web3Wrapper.awaitTransactionSuccessAsync(
- await authorizable.addAuthorizedAddress.sendTransactionAsync(address, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const index = new BigNumber(0);
- return expectTransactionFailedAsync(
- authorizable.removeAuthorizedAddressAtIndex.sendTransactionAsync(address, index, {
- from: notOwner,
- }),
- RevertReason.OnlyContractOwner,
- );
- });
- it('should throw if index is >= authorities.length', async () => {
- await web3Wrapper.awaitTransactionSuccessAsync(
- await authorizable.addAuthorizedAddress.sendTransactionAsync(address, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const index = new BigNumber(1);
- return expectTransactionFailedAsync(
- authorizable.removeAuthorizedAddressAtIndex.sendTransactionAsync(address, index, {
- from: owner,
- }),
- RevertReason.IndexOutOfBounds,
- );
- });
- it('should throw if owner attempts to remove an address that is not authorized', async () => {
- const index = new BigNumber(0);
- return expectTransactionFailedAsync(
- authorizable.removeAuthorizedAddressAtIndex.sendTransactionAsync(address, index, {
- from: owner,
- }),
- RevertReason.TargetNotAuthorized,
- );
- });
- it('should throw if address at index does not match target', async () => {
- const address1 = address;
- const address2 = notOwner;
- await web3Wrapper.awaitTransactionSuccessAsync(
- await authorizable.addAuthorizedAddress.sendTransactionAsync(address1, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await authorizable.addAuthorizedAddress.sendTransactionAsync(address2, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const address1Index = new BigNumber(0);
- return expectTransactionFailedAsync(
- authorizable.removeAuthorizedAddressAtIndex.sendTransactionAsync(address2, address1Index, {
- from: owner,
- }),
- RevertReason.AuthorizedAddressMismatch,
- );
- });
- it('should allow owner to remove an authorized address', async () => {
- await web3Wrapper.awaitTransactionSuccessAsync(
- await authorizable.addAuthorizedAddress.sendTransactionAsync(address, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const index = new BigNumber(0);
- await web3Wrapper.awaitTransactionSuccessAsync(
- await authorizable.removeAuthorizedAddressAtIndex.sendTransactionAsync(address, index, {
- from: owner,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const isAuthorized = await authorizable.authorized.callAsync(address);
- expect(isAuthorized).to.be.false();
- });
- });
-
- describe('getAuthorizedAddresses', () => {
- it('should return all authorized addresses', async () => {
- const initial = await authorizable.getAuthorizedAddresses.callAsync();
- expect(initial).to.have.length(0);
- await web3Wrapper.awaitTransactionSuccessAsync(
- await authorizable.addAuthorizedAddress.sendTransactionAsync(address, {
- from: owner,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const afterAdd = await authorizable.getAuthorizedAddresses.callAsync();
- expect(afterAdd).to.have.length(1);
- expect(afterAdd).to.include(address);
-
- await web3Wrapper.awaitTransactionSuccessAsync(
- await authorizable.removeAuthorizedAddress.sendTransactionAsync(address, {
- from: owner,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const afterRemove = await authorizable.getAuthorizedAddresses.callAsync();
- expect(afterRemove).to.have.length(0);
- });
- });
-});
diff --git a/packages/contracts/test/asset_proxy/proxies.ts b/packages/contracts/test/asset_proxy/proxies.ts
deleted file mode 100644
index 8fa1e602a..000000000
--- a/packages/contracts/test/asset_proxy/proxies.ts
+++ /dev/null
@@ -1,1246 +0,0 @@
-import { BlockchainLifecycle } from '@0x/dev-utils';
-import { assetDataUtils } from '@0x/order-utils';
-import { RevertReason } from '@0x/types';
-import { BigNumber } from '@0x/utils';
-import * as chai from 'chai';
-import * as _ from 'lodash';
-
-import { DummyERC20TokenContract } from '../../generated-wrappers/dummy_erc20_token';
-import { DummyERC721ReceiverContract } from '../../generated-wrappers/dummy_erc721_receiver';
-import { DummyERC721TokenContract } from '../../generated-wrappers/dummy_erc721_token';
-import { DummyMultipleReturnERC20TokenContract } from '../../generated-wrappers/dummy_multiple_return_erc20_token';
-import { DummyNoReturnERC20TokenContract } from '../../generated-wrappers/dummy_no_return_erc20_token';
-import { ERC20ProxyContract } from '../../generated-wrappers/erc20_proxy';
-import { ERC721ProxyContract } from '../../generated-wrappers/erc721_proxy';
-import { IAssetDataContract } from '../../generated-wrappers/i_asset_data';
-import { IAssetProxyContract } from '../../generated-wrappers/i_asset_proxy';
-import { MultiAssetProxyContract } from '../../generated-wrappers/multi_asset_proxy';
-import { artifacts } from '../../src/artifacts';
-import { expectTransactionFailedAsync, expectTransactionFailedWithoutReasonAsync } from '../utils/assertions';
-import { chaiSetup } from '../utils/chai_setup';
-import { constants } from '../utils/constants';
-import { ERC20Wrapper } from '../utils/erc20_wrapper';
-import { ERC721Wrapper } from '../utils/erc721_wrapper';
-import { LogDecoder } from '../utils/log_decoder';
-import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper';
-
-chaiSetup.configure();
-const expect = chai.expect;
-const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
-const assetProxyInterface = new IAssetProxyContract(
- artifacts.IAssetProxy.compilerOutput.abi,
- constants.NULL_ADDRESS,
- provider,
-);
-const assetDataInterface = new IAssetDataContract(
- artifacts.IAssetData.compilerOutput.abi,
- constants.NULL_ADDRESS,
- provider,
-);
-
-// tslint:disable:no-unnecessary-type-assertion
-describe('Asset Transfer Proxies', () => {
- let owner: string;
- let notAuthorized: string;
- let authorized: string;
- let fromAddress: string;
- let toAddress: string;
-
- let erc20TokenA: DummyERC20TokenContract;
- let erc20TokenB: DummyERC20TokenContract;
- let erc721TokenA: DummyERC721TokenContract;
- let erc721TokenB: DummyERC721TokenContract;
- let erc721Receiver: DummyERC721ReceiverContract;
- let erc20Proxy: ERC20ProxyContract;
- let erc721Proxy: ERC721ProxyContract;
- let noReturnErc20Token: DummyNoReturnERC20TokenContract;
- let multipleReturnErc20Token: DummyMultipleReturnERC20TokenContract;
- let multiAssetProxy: MultiAssetProxyContract;
-
- let erc20Wrapper: ERC20Wrapper;
- let erc721Wrapper: ERC721Wrapper;
- let erc721AFromTokenId: BigNumber;
- let erc721BFromTokenId: BigNumber;
-
- before(async () => {
- await blockchainLifecycle.startAsync();
- });
- after(async () => {
- await blockchainLifecycle.revertAsync();
- });
- before(async () => {
- const accounts = await web3Wrapper.getAvailableAddressesAsync();
- const usedAddresses = ([owner, notAuthorized, authorized, fromAddress, toAddress] = _.slice(accounts, 0, 5));
-
- erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner);
- erc721Wrapper = new ERC721Wrapper(provider, usedAddresses, owner);
-
- // Deploy AssetProxies
- erc20Proxy = await erc20Wrapper.deployProxyAsync();
- erc721Proxy = await erc721Wrapper.deployProxyAsync();
- multiAssetProxy = await MultiAssetProxyContract.deployFrom0xArtifactAsync(
- artifacts.MultiAssetProxy,
- provider,
- txDefaults,
- );
-
- // Configure ERC20Proxy
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc20Proxy.addAuthorizedAddress.sendTransactionAsync(authorized, {
- from: owner,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc20Proxy.addAuthorizedAddress.sendTransactionAsync(multiAssetProxy.address, {
- from: owner,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
-
- // Configure ERC721Proxy
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc721Proxy.addAuthorizedAddress.sendTransactionAsync(authorized, {
- from: owner,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc721Proxy.addAuthorizedAddress.sendTransactionAsync(multiAssetProxy.address, {
- from: owner,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
-
- // Configure MultiAssetProxy
- await web3Wrapper.awaitTransactionSuccessAsync(
- await multiAssetProxy.addAuthorizedAddress.sendTransactionAsync(authorized, {
- from: owner,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await multiAssetProxy.registerAssetProxy.sendTransactionAsync(erc20Proxy.address, {
- from: owner,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await multiAssetProxy.registerAssetProxy.sendTransactionAsync(erc721Proxy.address, {
- from: owner,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
-
- // Deploy and configure ERC20 tokens
- const numDummyErc20ToDeploy = 2;
- [erc20TokenA, erc20TokenB] = await erc20Wrapper.deployDummyTokensAsync(
- numDummyErc20ToDeploy,
- constants.DUMMY_TOKEN_DECIMALS,
- );
- noReturnErc20Token = await DummyNoReturnERC20TokenContract.deployFrom0xArtifactAsync(
- artifacts.DummyNoReturnERC20Token,
- provider,
- txDefaults,
- constants.DUMMY_TOKEN_NAME,
- constants.DUMMY_TOKEN_SYMBOL,
- constants.DUMMY_TOKEN_DECIMALS,
- constants.DUMMY_TOKEN_TOTAL_SUPPLY,
- );
- multipleReturnErc20Token = await DummyMultipleReturnERC20TokenContract.deployFrom0xArtifactAsync(
- artifacts.DummyMultipleReturnERC20Token,
- provider,
- txDefaults,
- constants.DUMMY_TOKEN_NAME,
- constants.DUMMY_TOKEN_SYMBOL,
- constants.DUMMY_TOKEN_DECIMALS,
- constants.DUMMY_TOKEN_TOTAL_SUPPLY,
- );
-
- await erc20Wrapper.setBalancesAndAllowancesAsync();
- await web3Wrapper.awaitTransactionSuccessAsync(
- await noReturnErc20Token.setBalance.sendTransactionAsync(fromAddress, constants.INITIAL_ERC20_BALANCE),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await noReturnErc20Token.approve.sendTransactionAsync(
- erc20Proxy.address,
- constants.INITIAL_ERC20_ALLOWANCE,
- { from: fromAddress },
- ),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await multipleReturnErc20Token.setBalance.sendTransactionAsync(
- fromAddress,
- constants.INITIAL_ERC20_BALANCE,
- ),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await multipleReturnErc20Token.approve.sendTransactionAsync(
- erc20Proxy.address,
- constants.INITIAL_ERC20_ALLOWANCE,
- { from: fromAddress },
- ),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
-
- // Deploy and configure ERC721 tokens and receiver
- [erc721TokenA, erc721TokenB] = await erc721Wrapper.deployDummyTokensAsync();
- erc721Receiver = await DummyERC721ReceiverContract.deployFrom0xArtifactAsync(
- artifacts.DummyERC721Receiver,
- provider,
- txDefaults,
- );
-
- await erc721Wrapper.setBalancesAndAllowancesAsync();
- const erc721Balances = await erc721Wrapper.getBalancesAsync();
- erc721AFromTokenId = erc721Balances[fromAddress][erc721TokenA.address][0];
- erc721BFromTokenId = erc721Balances[fromAddress][erc721TokenB.address][0];
- });
- beforeEach(async () => {
- await blockchainLifecycle.startAsync();
- });
- afterEach(async () => {
- await blockchainLifecycle.revertAsync();
- });
-
- describe('ERC20Proxy', () => {
- it('should revert if undefined function is called', async () => {
- const undefinedSelector = '0x01020304';
- await expectTransactionFailedWithoutReasonAsync(
- web3Wrapper.sendTransactionAsync({
- from: owner,
- to: erc20Proxy.address,
- value: constants.ZERO_AMOUNT,
- data: undefinedSelector,
- }),
- );
- });
- it('should have an id of 0xf47261b0', async () => {
- const proxyId = await erc20Proxy.getProxyId.callAsync();
- const expectedProxyId = '0xf47261b0';
- expect(proxyId).to.equal(expectedProxyId);
- });
- describe('transferFrom', () => {
- it('should successfully transfer tokens', async () => {
- // Construct ERC20 asset data
- const encodedAssetData = assetDataUtils.encodeERC20AssetData(erc20TokenA.address);
- // Perform a transfer from fromAddress to toAddress
- const erc20Balances = await erc20Wrapper.getBalancesAsync();
- const amount = new BigNumber(10);
- const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
- encodedAssetData,
- fromAddress,
- toAddress,
- amount,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await web3Wrapper.sendTransactionAsync({
- to: erc20Proxy.address,
- data,
- from: authorized,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- // Verify transfer was successful
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(newBalances[fromAddress][erc20TokenA.address]).to.be.bignumber.equal(
- erc20Balances[fromAddress][erc20TokenA.address].minus(amount),
- );
- expect(newBalances[toAddress][erc20TokenA.address]).to.be.bignumber.equal(
- erc20Balances[toAddress][erc20TokenA.address].add(amount),
- );
- });
-
- it('should successfully transfer tokens that do not return a value', async () => {
- // Construct ERC20 asset data
- const encodedAssetData = assetDataUtils.encodeERC20AssetData(noReturnErc20Token.address);
- // Perform a transfer from fromAddress to toAddress
- const initialFromBalance = await noReturnErc20Token.balanceOf.callAsync(fromAddress);
- const initialToBalance = await noReturnErc20Token.balanceOf.callAsync(toAddress);
- const amount = new BigNumber(10);
- const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
- encodedAssetData,
- fromAddress,
- toAddress,
- amount,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await web3Wrapper.sendTransactionAsync({
- to: erc20Proxy.address,
- data,
- from: authorized,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- // Verify transfer was successful
- const newFromBalance = await noReturnErc20Token.balanceOf.callAsync(fromAddress);
- const newToBalance = await noReturnErc20Token.balanceOf.callAsync(toAddress);
- expect(newFromBalance).to.be.bignumber.equal(initialFromBalance.minus(amount));
- expect(newToBalance).to.be.bignumber.equal(initialToBalance.plus(amount));
- });
-
- it('should successfully transfer tokens and ignore extra assetData', async () => {
- // Construct ERC20 asset data
- const extraData = '0102030405060708';
- const encodedAssetData = `${assetDataUtils.encodeERC20AssetData(erc20TokenA.address)}${extraData}`;
- // Perform a transfer from fromAddress to toAddress
- const erc20Balances = await erc20Wrapper.getBalancesAsync();
- const amount = new BigNumber(10);
- const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
- encodedAssetData,
- fromAddress,
- toAddress,
- amount,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await web3Wrapper.sendTransactionAsync({
- to: erc20Proxy.address,
- data,
- from: authorized,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- // Verify transfer was successful
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(newBalances[fromAddress][erc20TokenA.address]).to.be.bignumber.equal(
- erc20Balances[fromAddress][erc20TokenA.address].minus(amount),
- );
- expect(newBalances[toAddress][erc20TokenA.address]).to.be.bignumber.equal(
- erc20Balances[toAddress][erc20TokenA.address].add(amount),
- );
- });
-
- it('should do nothing if transferring 0 amount of a token', async () => {
- // Construct ERC20 asset data
- const encodedAssetData = assetDataUtils.encodeERC20AssetData(erc20TokenA.address);
- // Perform a transfer from fromAddress to toAddress
- const erc20Balances = await erc20Wrapper.getBalancesAsync();
- const amount = new BigNumber(0);
- const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
- encodedAssetData,
- fromAddress,
- toAddress,
- amount,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await web3Wrapper.sendTransactionAsync({
- to: erc20Proxy.address,
- data,
- from: authorized,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- // Verify transfer was successful
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(newBalances[fromAddress][erc20TokenA.address]).to.be.bignumber.equal(
- erc20Balances[fromAddress][erc20TokenA.address],
- );
- expect(newBalances[toAddress][erc20TokenA.address]).to.be.bignumber.equal(
- erc20Balances[toAddress][erc20TokenA.address],
- );
- });
-
- it('should revert if allowances are too low', async () => {
- // Construct ERC20 asset data
- const encodedAssetData = assetDataUtils.encodeERC20AssetData(erc20TokenA.address);
- // Create allowance less than transfer amount. Set allowance on proxy.
- const allowance = new BigNumber(0);
- const amount = new BigNumber(10);
- const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
- encodedAssetData,
- fromAddress,
- toAddress,
- amount,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc20TokenA.approve.sendTransactionAsync(erc20Proxy.address, allowance, {
- from: fromAddress,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const erc20Balances = await erc20Wrapper.getBalancesAsync();
- // Perform a transfer; expect this to fail.
- await expectTransactionFailedAsync(
- web3Wrapper.sendTransactionAsync({
- to: erc20Proxy.address,
- data,
- from: authorized,
- }),
- RevertReason.TransferFailed,
- );
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(newBalances).to.deep.equal(erc20Balances);
- });
-
- it('should revert if allowances are too low and token does not return a value', async () => {
- // Construct ERC20 asset data
- const encodedAssetData = assetDataUtils.encodeERC20AssetData(noReturnErc20Token.address);
- // Create allowance less than transfer amount. Set allowance on proxy.
- const allowance = new BigNumber(0);
- const amount = new BigNumber(10);
- const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
- encodedAssetData,
- fromAddress,
- toAddress,
- amount,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await noReturnErc20Token.approve.sendTransactionAsync(erc20Proxy.address, allowance, {
- from: fromAddress,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const initialFromBalance = await noReturnErc20Token.balanceOf.callAsync(fromAddress);
- const initialToBalance = await noReturnErc20Token.balanceOf.callAsync(toAddress);
- // Perform a transfer; expect this to fail.
- await expectTransactionFailedAsync(
- web3Wrapper.sendTransactionAsync({
- to: erc20Proxy.address,
- data,
- from: authorized,
- }),
- RevertReason.TransferFailed,
- );
- const newFromBalance = await noReturnErc20Token.balanceOf.callAsync(fromAddress);
- const newToBalance = await noReturnErc20Token.balanceOf.callAsync(toAddress);
- expect(newFromBalance).to.be.bignumber.equal(initialFromBalance);
- expect(newToBalance).to.be.bignumber.equal(initialToBalance);
- });
-
- it('should revert if caller is not authorized', async () => {
- // Construct ERC20 asset data
- const encodedAssetData = assetDataUtils.encodeERC20AssetData(erc20TokenA.address);
- // Perform a transfer from fromAddress to toAddress
- const amount = new BigNumber(10);
- const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
- encodedAssetData,
- fromAddress,
- toAddress,
- amount,
- );
- const erc20Balances = await erc20Wrapper.getBalancesAsync();
- await expectTransactionFailedAsync(
- web3Wrapper.sendTransactionAsync({
- to: erc20Proxy.address,
- data,
- from: notAuthorized,
- }),
- RevertReason.SenderNotAuthorized,
- );
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(newBalances).to.deep.equal(erc20Balances);
- });
-
- it('should revert if token returns more than 32 bytes', async () => {
- // Construct ERC20 asset data
- const encodedAssetData = assetDataUtils.encodeERC20AssetData(multipleReturnErc20Token.address);
- const amount = new BigNumber(10);
- const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
- encodedAssetData,
- fromAddress,
- toAddress,
- amount,
- );
- const initialFromBalance = await multipleReturnErc20Token.balanceOf.callAsync(fromAddress);
- const initialToBalance = await multipleReturnErc20Token.balanceOf.callAsync(toAddress);
- // Perform a transfer; expect this to fail.
- await expectTransactionFailedAsync(
- web3Wrapper.sendTransactionAsync({
- to: erc20Proxy.address,
- data,
- from: authorized,
- }),
- RevertReason.TransferFailed,
- );
- const newFromBalance = await multipleReturnErc20Token.balanceOf.callAsync(fromAddress);
- const newToBalance = await multipleReturnErc20Token.balanceOf.callAsync(toAddress);
- expect(newFromBalance).to.be.bignumber.equal(initialFromBalance);
- expect(newToBalance).to.be.bignumber.equal(initialToBalance);
- });
- });
- });
-
- describe('ERC721Proxy', () => {
- it('should revert if undefined function is called', async () => {
- const undefinedSelector = '0x01020304';
- await expectTransactionFailedWithoutReasonAsync(
- web3Wrapper.sendTransactionAsync({
- from: owner,
- to: erc721Proxy.address,
- value: constants.ZERO_AMOUNT,
- data: undefinedSelector,
- }),
- );
- });
- it('should have an id of 0x02571792', async () => {
- const proxyId = await erc721Proxy.getProxyId.callAsync();
- const expectedProxyId = '0x02571792';
- expect(proxyId).to.equal(expectedProxyId);
- });
- describe('transferFrom', () => {
- it('should successfully transfer tokens', async () => {
- // Construct ERC721 asset data
- const encodedAssetData = assetDataUtils.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
- // Verify pre-condition
- const ownerFromAsset = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
- expect(ownerFromAsset).to.be.equal(fromAddress);
- // Perform a transfer from fromAddress to toAddress
- const amount = new BigNumber(1);
- const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
- encodedAssetData,
- fromAddress,
- toAddress,
- amount,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await web3Wrapper.sendTransactionAsync({
- to: erc721Proxy.address,
- data,
- from: authorized,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- // Verify transfer was successful
- const newOwnerFromAsset = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
- expect(newOwnerFromAsset).to.be.bignumber.equal(toAddress);
- });
-
- it('should successfully transfer tokens and ignore extra assetData', async () => {
- // Construct ERC721 asset data
- const extraData = '0102030405060708';
- const encodedAssetData = `${assetDataUtils.encodeERC721AssetData(
- erc721TokenA.address,
- erc721AFromTokenId,
- )}${extraData}`;
- // Verify pre-condition
- const ownerFromAsset = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
- expect(ownerFromAsset).to.be.equal(fromAddress);
- // Perform a transfer from fromAddress to toAddress
- const amount = new BigNumber(1);
- const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
- encodedAssetData,
- fromAddress,
- toAddress,
- amount,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await web3Wrapper.sendTransactionAsync({
- to: erc721Proxy.address,
- data,
- from: authorized,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- // Verify transfer was successful
- const newOwnerFromAsset = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
- expect(newOwnerFromAsset).to.be.bignumber.equal(toAddress);
- });
-
- it('should not call onERC721Received when transferring to a smart contract', async () => {
- // Construct ERC721 asset data
- const encodedAssetData = assetDataUtils.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
- // Verify pre-condition
- const ownerFromAsset = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
- expect(ownerFromAsset).to.be.equal(fromAddress);
- // Perform a transfer from fromAddress to toAddress
- const amount = new BigNumber(1);
- const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
- encodedAssetData,
- fromAddress,
- erc721Receiver.address,
- amount,
- );
- const logDecoder = new LogDecoder(web3Wrapper);
- const tx = await logDecoder.getTxWithDecodedLogsAsync(
- await web3Wrapper.sendTransactionAsync({
- to: erc721Proxy.address,
- data,
- from: authorized,
- gas: constants.MAX_TRANSFER_FROM_GAS,
- }),
- );
- // Verify that no log was emitted by erc721 receiver
- expect(tx.logs.length).to.be.equal(1);
- // Verify transfer was successful
- const newOwnerFromAsset = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
- expect(newOwnerFromAsset).to.be.bignumber.equal(erc721Receiver.address);
- });
-
- it('should revert if transferring 0 amount of a token', async () => {
- // Construct ERC721 asset data
- const encodedAssetData = assetDataUtils.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
- // Verify pre-condition
- const ownerFromAsset = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
- expect(ownerFromAsset).to.be.equal(fromAddress);
- // Perform a transfer from fromAddress to toAddress
- const amount = new BigNumber(0);
- const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
- encodedAssetData,
- fromAddress,
- toAddress,
- amount,
- );
- await expectTransactionFailedAsync(
- web3Wrapper.sendTransactionAsync({
- to: erc721Proxy.address,
- data,
- from: authorized,
- }),
- RevertReason.InvalidAmount,
- );
- const newOwner = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
- expect(newOwner).to.be.equal(ownerFromAsset);
- });
-
- it('should revert if transferring > 1 amount of a token', async () => {
- // Construct ERC721 asset data
- const encodedAssetData = assetDataUtils.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
- // Verify pre-condition
- const ownerFromAsset = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
- expect(ownerFromAsset).to.be.equal(fromAddress);
- // Perform a transfer from fromAddress to toAddress
- const amount = new BigNumber(500);
- const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
- encodedAssetData,
- fromAddress,
- toAddress,
- amount,
- );
- await expectTransactionFailedAsync(
- web3Wrapper.sendTransactionAsync({
- to: erc721Proxy.address,
- data,
- from: authorized,
- }),
- RevertReason.InvalidAmount,
- );
- const newOwner = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
- expect(newOwner).to.be.equal(ownerFromAsset);
- });
-
- it('should revert if allowances are too low', async () => {
- // Construct ERC721 asset data
- const encodedAssetData = assetDataUtils.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
- // Verify pre-condition
- const ownerFromAsset = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
- expect(ownerFromAsset).to.be.equal(fromAddress);
- // Remove transfer approval for fromAddress.
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc721TokenA.approve.sendTransactionAsync(constants.NULL_ADDRESS, erc721AFromTokenId, {
- from: fromAddress,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- // Perform a transfer; expect this to fail.
- const amount = new BigNumber(1);
- const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
- encodedAssetData,
- fromAddress,
- toAddress,
- amount,
- );
- await expectTransactionFailedAsync(
- web3Wrapper.sendTransactionAsync({
- to: erc721Proxy.address,
- data,
- from: authorized,
- }),
- RevertReason.TransferFailed,
- );
- const newOwner = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
- expect(newOwner).to.be.equal(ownerFromAsset);
- });
-
- it('should revert if caller is not authorized', async () => {
- // Construct ERC721 asset data
- const encodedAssetData = assetDataUtils.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
- // Verify pre-condition
- const ownerFromAsset = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
- expect(ownerFromAsset).to.be.equal(fromAddress);
- // Perform a transfer from fromAddress to toAddress
- const amount = new BigNumber(1);
- const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
- encodedAssetData,
- fromAddress,
- toAddress,
- amount,
- );
- await expectTransactionFailedAsync(
- web3Wrapper.sendTransactionAsync({
- to: erc721Proxy.address,
- data,
- from: notAuthorized,
- }),
- RevertReason.SenderNotAuthorized,
- );
- const newOwner = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
- expect(newOwner).to.be.equal(ownerFromAsset);
- });
- });
- });
- describe('MultiAssetProxy', () => {
- it('should revert if undefined function is called', async () => {
- const undefinedSelector = '0x01020304';
- await expectTransactionFailedWithoutReasonAsync(
- web3Wrapper.sendTransactionAsync({
- from: owner,
- to: multiAssetProxy.address,
- value: constants.ZERO_AMOUNT,
- data: undefinedSelector,
- }),
- );
- });
- it('should have an id of 0x94cfcdd7', async () => {
- const proxyId = await multiAssetProxy.getProxyId.callAsync();
- // first 4 bytes of `keccak256('MultiAsset(uint256[],bytes[])')`
- const expectedProxyId = '0x94cfcdd7';
- expect(proxyId).to.equal(expectedProxyId);
- });
- describe('transferFrom', () => {
- it('should transfer a single ERC20 token', async () => {
- const inputAmount = new BigNumber(1);
- const erc20Amount = new BigNumber(10);
- const erc20AssetData = assetDataUtils.encodeERC20AssetData(erc20TokenA.address);
- const amounts = [erc20Amount];
- const nestedAssetData = [erc20AssetData];
- const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
- const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
- assetData,
- fromAddress,
- toAddress,
- inputAmount,
- );
- const erc20Balances = await erc20Wrapper.getBalancesAsync();
- await web3Wrapper.awaitTransactionSuccessAsync(
- await web3Wrapper.sendTransactionAsync({
- to: multiAssetProxy.address,
- data,
- from: authorized,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const newBalances = await erc20Wrapper.getBalancesAsync();
- const totalAmount = inputAmount.times(erc20Amount);
- expect(newBalances[fromAddress][erc20TokenA.address]).to.be.bignumber.equal(
- erc20Balances[fromAddress][erc20TokenA.address].minus(totalAmount),
- );
- expect(newBalances[toAddress][erc20TokenA.address]).to.be.bignumber.equal(
- erc20Balances[toAddress][erc20TokenA.address].add(totalAmount),
- );
- });
- it('should successfully transfer multiple of the same ERC20 token', async () => {
- const inputAmount = new BigNumber(1);
- const erc20Amount1 = new BigNumber(10);
- const erc20Amount2 = new BigNumber(20);
- const erc20AssetData1 = assetDataUtils.encodeERC20AssetData(erc20TokenA.address);
- const erc20AssetData2 = assetDataUtils.encodeERC20AssetData(erc20TokenA.address);
- const amounts = [erc20Amount1, erc20Amount2];
- const nestedAssetData = [erc20AssetData1, erc20AssetData2];
- const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
- const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
- assetData,
- fromAddress,
- toAddress,
- inputAmount,
- );
- const erc20Balances = await erc20Wrapper.getBalancesAsync();
- await web3Wrapper.awaitTransactionSuccessAsync(
- await web3Wrapper.sendTransactionAsync({
- to: multiAssetProxy.address,
- data,
- from: authorized,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const newBalances = await erc20Wrapper.getBalancesAsync();
- const totalAmount = inputAmount.times(erc20Amount1).plus(inputAmount.times(erc20Amount2));
- expect(newBalances[fromAddress][erc20TokenA.address]).to.be.bignumber.equal(
- erc20Balances[fromAddress][erc20TokenA.address].minus(totalAmount),
- );
- expect(newBalances[toAddress][erc20TokenA.address]).to.be.bignumber.equal(
- erc20Balances[toAddress][erc20TokenA.address].add(totalAmount),
- );
- });
- it('should successfully transfer multiple different ERC20 tokens', async () => {
- const inputAmount = new BigNumber(1);
- const erc20Amount1 = new BigNumber(10);
- const erc20Amount2 = new BigNumber(20);
- const erc20AssetData1 = assetDataUtils.encodeERC20AssetData(erc20TokenA.address);
- const erc20AssetData2 = assetDataUtils.encodeERC20AssetData(erc20TokenB.address);
- const amounts = [erc20Amount1, erc20Amount2];
- const nestedAssetData = [erc20AssetData1, erc20AssetData2];
- const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
- const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
- assetData,
- fromAddress,
- toAddress,
- inputAmount,
- );
- const erc20Balances = await erc20Wrapper.getBalancesAsync();
- await web3Wrapper.awaitTransactionSuccessAsync(
- await web3Wrapper.sendTransactionAsync({
- to: multiAssetProxy.address,
- data,
- from: authorized,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const newBalances = await erc20Wrapper.getBalancesAsync();
- const totalErc20AAmount = inputAmount.times(erc20Amount1);
- const totalErc20BAmount = inputAmount.times(erc20Amount2);
- expect(newBalances[fromAddress][erc20TokenA.address]).to.be.bignumber.equal(
- erc20Balances[fromAddress][erc20TokenA.address].minus(totalErc20AAmount),
- );
- expect(newBalances[toAddress][erc20TokenA.address]).to.be.bignumber.equal(
- erc20Balances[toAddress][erc20TokenA.address].add(totalErc20AAmount),
- );
- expect(newBalances[fromAddress][erc20TokenB.address]).to.be.bignumber.equal(
- erc20Balances[fromAddress][erc20TokenB.address].minus(totalErc20BAmount),
- );
- expect(newBalances[toAddress][erc20TokenB.address]).to.be.bignumber.equal(
- erc20Balances[toAddress][erc20TokenB.address].add(totalErc20BAmount),
- );
- });
- it('should transfer a single ERC721 token', async () => {
- const inputAmount = new BigNumber(1);
- const erc721Amount = new BigNumber(1);
- const erc721AssetData = assetDataUtils.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
- const amounts = [erc721Amount];
- const nestedAssetData = [erc721AssetData];
- const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
- const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
- assetData,
- fromAddress,
- toAddress,
- inputAmount,
- );
- const ownerFromAsset = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
- expect(ownerFromAsset).to.be.equal(fromAddress);
- await web3Wrapper.awaitTransactionSuccessAsync(
- await web3Wrapper.sendTransactionAsync({
- to: multiAssetProxy.address,
- data,
- from: authorized,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const newOwnerFromAsset = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
- expect(newOwnerFromAsset).to.be.equal(toAddress);
- });
- it('should successfully transfer multiple of the same ERC721 token', async () => {
- const erc721Balances = await erc721Wrapper.getBalancesAsync();
- const erc721AFromTokenId2 = erc721Balances[fromAddress][erc721TokenA.address][1];
- const erc721AssetData1 = assetDataUtils.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
- const erc721AssetData2 = assetDataUtils.encodeERC721AssetData(
- erc721TokenA.address,
- erc721AFromTokenId2,
- );
- const inputAmount = new BigNumber(1);
- const erc721Amount = new BigNumber(1);
- const amounts = [erc721Amount, erc721Amount];
- const nestedAssetData = [erc721AssetData1, erc721AssetData2];
- const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
- const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
- assetData,
- fromAddress,
- toAddress,
- inputAmount,
- );
- const ownerFromAsset1 = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
- expect(ownerFromAsset1).to.be.equal(fromAddress);
- const ownerFromAsset2 = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId2);
- expect(ownerFromAsset2).to.be.equal(fromAddress);
- await web3Wrapper.awaitTransactionSuccessAsync(
- await web3Wrapper.sendTransactionAsync({
- to: multiAssetProxy.address,
- data,
- from: authorized,
- gas: constants.MAX_TRANSFER_FROM_GAS,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const newOwnerFromAsset1 = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
- const newOwnerFromAsset2 = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId2);
- expect(newOwnerFromAsset1).to.be.equal(toAddress);
- expect(newOwnerFromAsset2).to.be.equal(toAddress);
- });
- it('should successfully transfer multiple different ERC721 tokens', async () => {
- const erc721AssetData1 = assetDataUtils.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
- const erc721AssetData2 = assetDataUtils.encodeERC721AssetData(erc721TokenB.address, erc721BFromTokenId);
- const inputAmount = new BigNumber(1);
- const erc721Amount = new BigNumber(1);
- const amounts = [erc721Amount, erc721Amount];
- const nestedAssetData = [erc721AssetData1, erc721AssetData2];
- const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
- const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
- assetData,
- fromAddress,
- toAddress,
- inputAmount,
- );
- const ownerFromAsset1 = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
- expect(ownerFromAsset1).to.be.equal(fromAddress);
- const ownerFromAsset2 = await erc721TokenB.ownerOf.callAsync(erc721BFromTokenId);
- expect(ownerFromAsset2).to.be.equal(fromAddress);
- await web3Wrapper.awaitTransactionSuccessAsync(
- await web3Wrapper.sendTransactionAsync({
- to: multiAssetProxy.address,
- data,
- from: authorized,
- gas: constants.MAX_TRANSFER_FROM_GAS,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const newOwnerFromAsset1 = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
- const newOwnerFromAsset2 = await erc721TokenB.ownerOf.callAsync(erc721BFromTokenId);
- expect(newOwnerFromAsset1).to.be.equal(toAddress);
- expect(newOwnerFromAsset2).to.be.equal(toAddress);
- });
- it('should successfully transfer a combination of ERC20 and ERC721 tokens', async () => {
- const inputAmount = new BigNumber(1);
- const erc20Amount = new BigNumber(10);
- const erc20AssetData = assetDataUtils.encodeERC20AssetData(erc20TokenA.address);
- const erc721Amount = new BigNumber(1);
- const erc721AssetData = assetDataUtils.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
- const amounts = [erc20Amount, erc721Amount];
- const nestedAssetData = [erc20AssetData, erc721AssetData];
- const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
- const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
- assetData,
- fromAddress,
- toAddress,
- inputAmount,
- );
- const erc20Balances = await erc20Wrapper.getBalancesAsync();
- const ownerFromAsset = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
- expect(ownerFromAsset).to.be.equal(fromAddress);
- await web3Wrapper.awaitTransactionSuccessAsync(
- await web3Wrapper.sendTransactionAsync({
- to: multiAssetProxy.address,
- data,
- from: authorized,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const newBalances = await erc20Wrapper.getBalancesAsync();
- const totalAmount = inputAmount.times(erc20Amount);
- expect(newBalances[fromAddress][erc20TokenA.address]).to.be.bignumber.equal(
- erc20Balances[fromAddress][erc20TokenA.address].minus(totalAmount),
- );
- expect(newBalances[toAddress][erc20TokenA.address]).to.be.bignumber.equal(
- erc20Balances[toAddress][erc20TokenA.address].add(totalAmount),
- );
- const newOwnerFromAsset = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
- expect(newOwnerFromAsset).to.be.equal(toAddress);
- });
- it('should successfully transfer tokens and ignore extra assetData', async () => {
- const inputAmount = new BigNumber(1);
- const erc20Amount = new BigNumber(10);
- const erc20AssetData = assetDataUtils.encodeERC20AssetData(erc20TokenA.address);
- const erc721Amount = new BigNumber(1);
- const erc721AssetData = assetDataUtils.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
- const amounts = [erc20Amount, erc721Amount];
- const nestedAssetData = [erc20AssetData, erc721AssetData];
- const extraData = '0102030405060708';
- const assetData = `${assetDataInterface.MultiAsset.getABIEncodedTransactionData(
- amounts,
- nestedAssetData,
- )}${extraData}`;
- const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
- assetData,
- fromAddress,
- toAddress,
- inputAmount,
- );
- const erc20Balances = await erc20Wrapper.getBalancesAsync();
- const ownerFromAsset = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
- expect(ownerFromAsset).to.be.equal(fromAddress);
- await web3Wrapper.awaitTransactionSuccessAsync(
- await web3Wrapper.sendTransactionAsync({
- to: multiAssetProxy.address,
- data,
- from: authorized,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const newBalances = await erc20Wrapper.getBalancesAsync();
- const totalAmount = inputAmount.times(erc20Amount);
- expect(newBalances[fromAddress][erc20TokenA.address]).to.be.bignumber.equal(
- erc20Balances[fromAddress][erc20TokenA.address].minus(totalAmount),
- );
- expect(newBalances[toAddress][erc20TokenA.address]).to.be.bignumber.equal(
- erc20Balances[toAddress][erc20TokenA.address].add(totalAmount),
- );
- const newOwnerFromAsset = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
- expect(newOwnerFromAsset).to.be.equal(toAddress);
- });
- it('should successfully transfer correct amounts when the `amount` > 1', async () => {
- const inputAmount = new BigNumber(100);
- const erc20Amount1 = new BigNumber(10);
- const erc20Amount2 = new BigNumber(20);
- const erc20AssetData1 = assetDataUtils.encodeERC20AssetData(erc20TokenA.address);
- const erc20AssetData2 = assetDataUtils.encodeERC20AssetData(erc20TokenB.address);
- const amounts = [erc20Amount1, erc20Amount2];
- const nestedAssetData = [erc20AssetData1, erc20AssetData2];
- const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
- const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
- assetData,
- fromAddress,
- toAddress,
- inputAmount,
- );
- const erc20Balances = await erc20Wrapper.getBalancesAsync();
- await web3Wrapper.awaitTransactionSuccessAsync(
- await web3Wrapper.sendTransactionAsync({
- to: multiAssetProxy.address,
- data,
- from: authorized,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const newBalances = await erc20Wrapper.getBalancesAsync();
- const totalErc20AAmount = inputAmount.times(erc20Amount1);
- const totalErc20BAmount = inputAmount.times(erc20Amount2);
- expect(newBalances[fromAddress][erc20TokenA.address]).to.be.bignumber.equal(
- erc20Balances[fromAddress][erc20TokenA.address].minus(totalErc20AAmount),
- );
- expect(newBalances[toAddress][erc20TokenA.address]).to.be.bignumber.equal(
- erc20Balances[toAddress][erc20TokenA.address].add(totalErc20AAmount),
- );
- expect(newBalances[fromAddress][erc20TokenB.address]).to.be.bignumber.equal(
- erc20Balances[fromAddress][erc20TokenB.address].minus(totalErc20BAmount),
- );
- expect(newBalances[toAddress][erc20TokenB.address]).to.be.bignumber.equal(
- erc20Balances[toAddress][erc20TokenB.address].add(totalErc20BAmount),
- );
- });
- it('should successfully transfer a large amount of tokens', async () => {
- const inputAmount = new BigNumber(1);
- const erc20Amount1 = new BigNumber(10);
- const erc20Amount2 = new BigNumber(20);
- const erc20AssetData1 = assetDataUtils.encodeERC20AssetData(erc20TokenA.address);
- const erc20AssetData2 = assetDataUtils.encodeERC20AssetData(erc20TokenB.address);
- const erc721Amount = new BigNumber(1);
- const erc721Balances = await erc721Wrapper.getBalancesAsync();
- const erc721AFromTokenId2 = erc721Balances[fromAddress][erc721TokenA.address][1];
- const erc721BFromTokenId2 = erc721Balances[fromAddress][erc721TokenB.address][1];
- const erc721AssetData1 = assetDataUtils.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
- const erc721AssetData2 = assetDataUtils.encodeERC721AssetData(
- erc721TokenA.address,
- erc721AFromTokenId2,
- );
- const erc721AssetData3 = assetDataUtils.encodeERC721AssetData(erc721TokenB.address, erc721BFromTokenId);
- const erc721AssetData4 = assetDataUtils.encodeERC721AssetData(
- erc721TokenB.address,
- erc721BFromTokenId2,
- );
- const amounts = [erc721Amount, erc20Amount1, erc721Amount, erc20Amount2, erc721Amount, erc721Amount];
- const nestedAssetData = [
- erc721AssetData1,
- erc20AssetData1,
- erc721AssetData2,
- erc20AssetData2,
- erc721AssetData3,
- erc721AssetData4,
- ];
- const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
- const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
- assetData,
- fromAddress,
- toAddress,
- inputAmount,
- );
- const ownerFromAsset1 = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
- expect(ownerFromAsset1).to.be.equal(fromAddress);
- const ownerFromAsset2 = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId2);
- expect(ownerFromAsset2).to.be.equal(fromAddress);
- const ownerFromAsset3 = await erc721TokenB.ownerOf.callAsync(erc721BFromTokenId);
- expect(ownerFromAsset3).to.be.equal(fromAddress);
- const ownerFromAsset4 = await erc721TokenB.ownerOf.callAsync(erc721BFromTokenId2);
- expect(ownerFromAsset4).to.be.equal(fromAddress);
- const erc20Balances = await erc20Wrapper.getBalancesAsync();
- await web3Wrapper.awaitTransactionSuccessAsync(
- await web3Wrapper.sendTransactionAsync({
- to: multiAssetProxy.address,
- data,
- from: authorized,
- gas: constants.MAX_EXECUTE_TRANSACTION_GAS,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const newOwnerFromAsset1 = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
- const newOwnerFromAsset2 = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId2);
- const newOwnerFromAsset3 = await erc721TokenB.ownerOf.callAsync(erc721BFromTokenId);
- const newOwnerFromAsset4 = await erc721TokenB.ownerOf.callAsync(erc721BFromTokenId2);
- expect(newOwnerFromAsset1).to.be.equal(toAddress);
- expect(newOwnerFromAsset2).to.be.equal(toAddress);
- expect(newOwnerFromAsset3).to.be.equal(toAddress);
- expect(newOwnerFromAsset4).to.be.equal(toAddress);
- const newBalances = await erc20Wrapper.getBalancesAsync();
- const totalErc20AAmount = inputAmount.times(erc20Amount1);
- const totalErc20BAmount = inputAmount.times(erc20Amount2);
- expect(newBalances[fromAddress][erc20TokenA.address]).to.be.bignumber.equal(
- erc20Balances[fromAddress][erc20TokenA.address].minus(totalErc20AAmount),
- );
- expect(newBalances[toAddress][erc20TokenA.address]).to.be.bignumber.equal(
- erc20Balances[toAddress][erc20TokenA.address].add(totalErc20AAmount),
- );
- expect(newBalances[fromAddress][erc20TokenB.address]).to.be.bignumber.equal(
- erc20Balances[fromAddress][erc20TokenB.address].minus(totalErc20BAmount),
- );
- expect(newBalances[toAddress][erc20TokenB.address]).to.be.bignumber.equal(
- erc20Balances[toAddress][erc20TokenB.address].add(totalErc20BAmount),
- );
- });
- it('should revert if a single transfer fails', async () => {
- const inputAmount = new BigNumber(1);
- const erc20Amount = new BigNumber(10);
- const erc20AssetData = assetDataUtils.encodeERC20AssetData(erc20TokenA.address);
- // 2 is an invalid erc721 amount
- const erc721Amount = new BigNumber(2);
- const erc721AssetData = assetDataUtils.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
- const amounts = [erc20Amount, erc721Amount];
- const nestedAssetData = [erc20AssetData, erc721AssetData];
- const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
- const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
- assetData,
- fromAddress,
- toAddress,
- inputAmount,
- );
- await expectTransactionFailedAsync(
- web3Wrapper.sendTransactionAsync({
- to: multiAssetProxy.address,
- data,
- from: authorized,
- }),
- RevertReason.InvalidAmount,
- );
- });
- it('should revert if an AssetProxy is not registered', async () => {
- const inputAmount = new BigNumber(1);
- const erc20Amount = new BigNumber(10);
- const erc20AssetData = assetDataUtils.encodeERC20AssetData(erc20TokenA.address);
- const erc721Amount = new BigNumber(1);
- const erc721AssetData = assetDataUtils.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
- const invalidProxyId = '0x12345678';
- const invalidErc721AssetData = `${invalidProxyId}${erc721AssetData.slice(10)}`;
- const amounts = [erc20Amount, erc721Amount];
- const nestedAssetData = [erc20AssetData, invalidErc721AssetData];
- const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
- const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
- assetData,
- fromAddress,
- toAddress,
- inputAmount,
- );
- await expectTransactionFailedAsync(
- web3Wrapper.sendTransactionAsync({
- to: multiAssetProxy.address,
- data,
- from: authorized,
- }),
- RevertReason.AssetProxyDoesNotExist,
- );
- });
- it('should revert if the length of `amounts` does not match the length of `nestedAssetData`', async () => {
- const inputAmount = new BigNumber(1);
- const erc20Amount = new BigNumber(10);
- const erc20AssetData = assetDataUtils.encodeERC20AssetData(erc20TokenA.address);
- const erc721AssetData = assetDataUtils.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
- const amounts = [erc20Amount];
- const nestedAssetData = [erc20AssetData, erc721AssetData];
- const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
- const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
- assetData,
- fromAddress,
- toAddress,
- inputAmount,
- );
- await expectTransactionFailedAsync(
- web3Wrapper.sendTransactionAsync({
- to: multiAssetProxy.address,
- data,
- from: authorized,
- }),
- RevertReason.LengthMismatch,
- );
- });
- it('should revert if amounts multiplication results in an overflow', async () => {
- const inputAmount = new BigNumber(2).pow(128);
- const erc20Amount = new BigNumber(2).pow(128);
- const erc20AssetData = assetDataUtils.encodeERC20AssetData(erc20TokenA.address);
- const amounts = [erc20Amount];
- const nestedAssetData = [erc20AssetData];
- const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
- const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
- assetData,
- fromAddress,
- toAddress,
- inputAmount,
- );
- await expectTransactionFailedAsync(
- web3Wrapper.sendTransactionAsync({
- to: multiAssetProxy.address,
- data,
- from: authorized,
- }),
- RevertReason.Uint256Overflow,
- );
- });
- it('should revert if an element of `nestedAssetData` is < 4 bytes long', async () => {
- const inputAmount = new BigNumber(1);
- const erc20Amount = new BigNumber(10);
- const erc20AssetData = assetDataUtils.encodeERC20AssetData(erc20TokenA.address);
- const erc721Amount = new BigNumber(1);
- const erc721AssetData = '0x123456';
- const amounts = [erc20Amount, erc721Amount];
- const nestedAssetData = [erc20AssetData, erc721AssetData];
- const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
- const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
- assetData,
- fromAddress,
- toAddress,
- inputAmount,
- );
- await expectTransactionFailedAsync(
- web3Wrapper.sendTransactionAsync({
- to: multiAssetProxy.address,
- data,
- from: authorized,
- }),
- RevertReason.LengthGreaterThan3Required,
- );
- });
- it('should revert if caller is not authorized', async () => {
- const inputAmount = new BigNumber(1);
- const erc20Amount = new BigNumber(10);
- const erc20AssetData = assetDataUtils.encodeERC20AssetData(erc20TokenA.address);
- const erc721Amount = new BigNumber(1);
- const erc721AssetData = assetDataUtils.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
- const amounts = [erc20Amount, erc721Amount];
- const nestedAssetData = [erc20AssetData, erc721AssetData];
- const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
- const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
- assetData,
- fromAddress,
- toAddress,
- inputAmount,
- );
- await expectTransactionFailedAsync(
- web3Wrapper.sendTransactionAsync({
- to: multiAssetProxy.address,
- data,
- from: notAuthorized,
- }),
- RevertReason.SenderNotAuthorized,
- );
- });
- });
- });
-});
-// tslint:enable:no-unnecessary-type-assertion
-// tslint:disable:max-file-line-count
diff --git a/packages/contracts/test/exchange/core.ts b/packages/contracts/test/exchange/core.ts
deleted file mode 100644
index 9159b0d8f..000000000
--- a/packages/contracts/test/exchange/core.ts
+++ /dev/null
@@ -1,1168 +0,0 @@
-import { BlockchainLifecycle } from '@0x/dev-utils';
-import { assetDataUtils, orderHashUtils } from '@0x/order-utils';
-import { RevertReason, SignatureType, SignedOrder } 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 ethUtil = require('ethereumjs-util');
-import * as _ from 'lodash';
-
-import { DummyERC20TokenContract, DummyERC20TokenTransferEventArgs } from '../../generated-wrappers/dummy_erc20_token';
-import { DummyERC721TokenContract } from '../../generated-wrappers/dummy_erc721_token';
-import { DummyNoReturnERC20TokenContract } from '../../generated-wrappers/dummy_no_return_erc20_token';
-import { ERC20ProxyContract } from '../../generated-wrappers/erc20_proxy';
-import { ERC721ProxyContract } from '../../generated-wrappers/erc721_proxy';
-import { ExchangeCancelEventArgs, ExchangeContract } from '../../generated-wrappers/exchange';
-import { IAssetDataContract } from '../../generated-wrappers/i_asset_data';
-import { MultiAssetProxyContract } from '../../generated-wrappers/multi_asset_proxy';
-import { ReentrantERC20TokenContract } from '../../generated-wrappers/reentrant_erc20_token';
-import { TestStaticCallReceiverContract } from '../../generated-wrappers/test_static_call_receiver';
-import { artifacts } from '../../src/artifacts';
-import { expectTransactionFailedAsync } from '../utils/assertions';
-import { getLatestBlockTimestampAsync, increaseTimeAndMineBlockAsync } from '../utils/block_timestamp';
-import { chaiSetup } from '../utils/chai_setup';
-import { constants } from '../utils/constants';
-import { ERC20Wrapper } from '../utils/erc20_wrapper';
-import { ERC721Wrapper } from '../utils/erc721_wrapper';
-import { ExchangeWrapper } from '../utils/exchange_wrapper';
-import { OrderFactory } from '../utils/order_factory';
-import { ERC20BalancesByOwner, OrderStatus } from '../utils/types';
-import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper';
-
-chaiSetup.configure();
-const expect = chai.expect;
-const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
-const assetDataInterface = new IAssetDataContract(
- artifacts.IAssetData.compilerOutput.abi,
- constants.NULL_ADDRESS,
- provider,
-);
-// tslint:disable:no-unnecessary-type-assertion
-describe('Exchange core', () => {
- let makerAddress: string;
- let owner: string;
- let takerAddress: string;
- let feeRecipientAddress: string;
-
- let erc20TokenA: DummyERC20TokenContract;
- let erc20TokenB: DummyERC20TokenContract;
- let zrxToken: DummyERC20TokenContract;
- let erc721Token: DummyERC721TokenContract;
- let noReturnErc20Token: DummyNoReturnERC20TokenContract;
- let reentrantErc20Token: ReentrantERC20TokenContract;
- let exchange: ExchangeContract;
- let erc20Proxy: ERC20ProxyContract;
- let erc721Proxy: ERC721ProxyContract;
- let multiAssetProxy: MultiAssetProxyContract;
- let maliciousWallet: TestStaticCallReceiverContract;
- let maliciousValidator: TestStaticCallReceiverContract;
-
- let signedOrder: SignedOrder;
- let erc20Balances: ERC20BalancesByOwner;
- let exchangeWrapper: ExchangeWrapper;
- let erc20Wrapper: ERC20Wrapper;
- let erc721Wrapper: ERC721Wrapper;
- let orderFactory: OrderFactory;
-
- let erc721MakerAssetIds: BigNumber[];
- let erc721TakerAssetIds: BigNumber[];
-
- let defaultMakerAssetAddress: string;
- let defaultTakerAssetAddress: string;
-
- before(async () => {
- await blockchainLifecycle.startAsync();
- });
- after(async () => {
- await blockchainLifecycle.revertAsync();
- });
- before(async () => {
- const accounts = await web3Wrapper.getAvailableAddressesAsync();
- const usedAddresses = ([owner, makerAddress, takerAddress, feeRecipientAddress] = _.slice(accounts, 0, 4));
-
- erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner);
- erc721Wrapper = new ERC721Wrapper(provider, usedAddresses, owner);
-
- // Deploy AssetProxies, Exchange, tokens, and malicious contracts
- erc20Proxy = await erc20Wrapper.deployProxyAsync();
- erc721Proxy = await erc721Wrapper.deployProxyAsync();
- multiAssetProxy = await MultiAssetProxyContract.deployFrom0xArtifactAsync(
- artifacts.MultiAssetProxy,
- provider,
- txDefaults,
- );
- const numDummyErc20ToDeploy = 3;
- [erc20TokenA, erc20TokenB, zrxToken] = await erc20Wrapper.deployDummyTokensAsync(
- numDummyErc20ToDeploy,
- constants.DUMMY_TOKEN_DECIMALS,
- );
- [erc721Token] = await erc721Wrapper.deployDummyTokensAsync();
- exchange = await ExchangeContract.deployFrom0xArtifactAsync(
- artifacts.Exchange,
- provider,
- txDefaults,
- assetDataUtils.encodeERC20AssetData(zrxToken.address),
- );
- maliciousWallet = maliciousValidator = await TestStaticCallReceiverContract.deployFrom0xArtifactAsync(
- artifacts.TestStaticCallReceiver,
- provider,
- txDefaults,
- );
- reentrantErc20Token = await ReentrantERC20TokenContract.deployFrom0xArtifactAsync(
- artifacts.ReentrantERC20Token,
- provider,
- txDefaults,
- exchange.address,
- );
-
- // Configure ERC20Proxy
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc20Proxy.addAuthorizedAddress.sendTransactionAsync(exchange.address, {
- from: owner,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc20Proxy.addAuthorizedAddress.sendTransactionAsync(multiAssetProxy.address, {
- from: owner,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
-
- // Configure ERC721Proxy
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc721Proxy.addAuthorizedAddress.sendTransactionAsync(exchange.address, {
- from: owner,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc721Proxy.addAuthorizedAddress.sendTransactionAsync(multiAssetProxy.address, {
- from: owner,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
-
- // Configure MultiAssetProxy
- await web3Wrapper.awaitTransactionSuccessAsync(
- await multiAssetProxy.addAuthorizedAddress.sendTransactionAsync(exchange.address, {
- from: owner,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await multiAssetProxy.registerAssetProxy.sendTransactionAsync(erc20Proxy.address, {
- from: owner,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await multiAssetProxy.registerAssetProxy.sendTransactionAsync(erc721Proxy.address, {
- from: owner,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
-
- // Configure Exchange
- exchangeWrapper = new ExchangeWrapper(exchange, provider);
- await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner);
- await exchangeWrapper.registerAssetProxyAsync(erc721Proxy.address, owner);
- await exchangeWrapper.registerAssetProxyAsync(multiAssetProxy.address, owner);
-
- // Configure ERC20 tokens
- await erc20Wrapper.setBalancesAndAllowancesAsync();
-
- // Configure ERC721 tokens
- await erc721Wrapper.setBalancesAndAllowancesAsync();
- const erc721Balances = await erc721Wrapper.getBalancesAsync();
- erc721MakerAssetIds = erc721Balances[makerAddress][erc721Token.address];
- erc721TakerAssetIds = erc721Balances[takerAddress][erc721Token.address];
-
- // Configure order defaults
- defaultMakerAssetAddress = erc20TokenA.address;
- defaultTakerAssetAddress = erc20TokenB.address;
- const defaultOrderParams = {
- ...constants.STATIC_ORDER_PARAMS,
- exchangeAddress: exchange.address,
- makerAddress,
- feeRecipientAddress,
- makerAssetData: assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress),
- takerAssetData: assetDataUtils.encodeERC20AssetData(defaultTakerAssetAddress),
- };
- 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('fillOrder', () => {
- beforeEach(async () => {
- erc20Balances = await erc20Wrapper.getBalancesAsync();
- signedOrder = await orderFactory.newSignedOrderAsync();
- });
-
- const reentrancyTest = (functionNames: string[]) => {
- _.forEach(functionNames, async (functionName: string, functionId: number) => {
- const description = `should not allow fillOrder to reenter the Exchange contract via ${functionName}`;
- it(description, async () => {
- signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetData: assetDataUtils.encodeERC20AssetData(reentrantErc20Token.address),
- });
- await web3Wrapper.awaitTransactionSuccessAsync(
- await reentrantErc20Token.setCurrentFunction.sendTransactionAsync(functionId),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await expectTransactionFailedAsync(
- exchangeWrapper.fillOrderAsync(signedOrder, takerAddress),
- RevertReason.TransferFailed,
- );
- });
- });
- };
- describe('fillOrder reentrancy tests', () => reentrancyTest(constants.FUNCTIONS_WITH_MUTEX));
-
- it('should throw if signature is invalid', async () => {
- signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- });
-
- const v = ethUtil.toBuffer(signedOrder.signature.slice(0, 4));
- const invalidR = ethUtil.sha3('invalidR');
- const invalidS = ethUtil.sha3('invalidS');
- const signatureType = ethUtil.toBuffer(`0x${signedOrder.signature.slice(-2)}`);
- const invalidSigBuff = Buffer.concat([v, invalidR, invalidS, signatureType]);
- const invalidSigHex = `0x${invalidSigBuff.toString('hex')}`;
- signedOrder.signature = invalidSigHex;
- return expectTransactionFailedAsync(
- exchangeWrapper.fillOrderAsync(signedOrder, takerAddress),
- RevertReason.InvalidOrderSignature,
- );
- });
-
- it('should throw if no value is filled', async () => {
- signedOrder = await orderFactory.newSignedOrderAsync();
- await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress);
- return expectTransactionFailedAsync(
- exchangeWrapper.fillOrderAsync(signedOrder, takerAddress),
- RevertReason.OrderUnfillable,
- );
- });
-
- it('should revert if `isValidSignature` tries to update state when SignatureType=Wallet', async () => {
- const maliciousMakerAddress = maliciousWallet.address;
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc20TokenA.setBalance.sendTransactionAsync(
- maliciousMakerAddress,
- constants.INITIAL_ERC20_BALANCE,
- ),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await maliciousWallet.approveERC20.sendTransactionAsync(
- erc20TokenA.address,
- erc20Proxy.address,
- constants.INITIAL_ERC20_ALLOWANCE,
- ),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- signedOrder = await orderFactory.newSignedOrderAsync({
- makerAddress: maliciousMakerAddress,
- makerFee: constants.ZERO_AMOUNT,
- });
- signedOrder.signature = `0x0${SignatureType.Wallet}`;
- await expectTransactionFailedAsync(
- exchangeWrapper.fillOrderAsync(signedOrder, takerAddress),
- RevertReason.WalletError,
- );
- });
-
- it('should revert if `isValidSignature` tries to update state when SignatureType=Validator', async () => {
- const isApproved = true;
- await web3Wrapper.awaitTransactionSuccessAsync(
- await exchange.setSignatureValidatorApproval.sendTransactionAsync(
- maliciousValidator.address,
- isApproved,
- { from: makerAddress },
- ),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- signedOrder.signature = `${maliciousValidator.address}0${SignatureType.Validator}`;
- await expectTransactionFailedAsync(
- exchangeWrapper.fillOrderAsync(signedOrder, takerAddress),
- RevertReason.ValidatorError,
- );
- });
-
- it('should not emit transfer events for transfers where from == to', async () => {
- const txReceipt = await exchangeWrapper.fillOrderAsync(signedOrder, makerAddress);
- const logs = txReceipt.logs;
- const transferLogs = _.filter(
- logs,
- log => (log as LogWithDecodedArgs<DummyERC20TokenTransferEventArgs>).event === 'Transfer',
- );
- expect(transferLogs.length).to.be.equal(2);
- expect((transferLogs[0] as LogWithDecodedArgs<DummyERC20TokenTransferEventArgs>).address).to.be.equal(
- zrxToken.address,
- );
- expect((transferLogs[0] as LogWithDecodedArgs<DummyERC20TokenTransferEventArgs>).args._from).to.be.equal(
- makerAddress,
- );
- expect((transferLogs[0] as LogWithDecodedArgs<DummyERC20TokenTransferEventArgs>).args._to).to.be.equal(
- feeRecipientAddress,
- );
- expect(
- (transferLogs[0] as LogWithDecodedArgs<DummyERC20TokenTransferEventArgs>).args._value,
- ).to.be.bignumber.equal(signedOrder.makerFee);
- expect((transferLogs[1] as LogWithDecodedArgs<DummyERC20TokenTransferEventArgs>).address).to.be.equal(
- zrxToken.address,
- );
- expect((transferLogs[1] as LogWithDecodedArgs<DummyERC20TokenTransferEventArgs>).args._from).to.be.equal(
- makerAddress,
- );
- expect((transferLogs[1] as LogWithDecodedArgs<DummyERC20TokenTransferEventArgs>).args._to).to.be.equal(
- feeRecipientAddress,
- );
- expect(
- (transferLogs[1] as LogWithDecodedArgs<DummyERC20TokenTransferEventArgs>).args._value,
- ).to.be.bignumber.equal(signedOrder.takerFee);
- });
- });
-
- describe('Testing exchange of ERC20 tokens with no return values', () => {
- before(async () => {
- noReturnErc20Token = await DummyNoReturnERC20TokenContract.deployFrom0xArtifactAsync(
- artifacts.DummyNoReturnERC20Token,
- provider,
- txDefaults,
- constants.DUMMY_TOKEN_NAME,
- constants.DUMMY_TOKEN_SYMBOL,
- constants.DUMMY_TOKEN_DECIMALS,
- constants.DUMMY_TOKEN_TOTAL_SUPPLY,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await noReturnErc20Token.setBalance.sendTransactionAsync(makerAddress, constants.INITIAL_ERC20_BALANCE),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await noReturnErc20Token.approve.sendTransactionAsync(
- erc20Proxy.address,
- constants.INITIAL_ERC20_ALLOWANCE,
- { from: makerAddress },
- ),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- });
- it('should transfer the correct amounts when makerAssetAmount === takerAssetAmount', async () => {
- signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetData: assetDataUtils.encodeERC20AssetData(noReturnErc20Token.address),
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18),
- });
-
- const initialMakerBalanceA = await noReturnErc20Token.balanceOf.callAsync(makerAddress);
- const initialMakerBalanceB = await erc20TokenB.balanceOf.callAsync(makerAddress);
- const initialMakerZrxBalance = await zrxToken.balanceOf.callAsync(makerAddress);
- const initialTakerBalanceA = await noReturnErc20Token.balanceOf.callAsync(takerAddress);
- const initialTakerBalanceB = await erc20TokenB.balanceOf.callAsync(takerAddress);
- const initialTakerZrxBalance = await zrxToken.balanceOf.callAsync(takerAddress);
- const initialFeeRecipientZrxBalance = await zrxToken.balanceOf.callAsync(feeRecipientAddress);
-
- await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress);
-
- const finalMakerBalanceA = await noReturnErc20Token.balanceOf.callAsync(makerAddress);
- const finalMakerBalanceB = await erc20TokenB.balanceOf.callAsync(makerAddress);
- const finalMakerZrxBalance = await zrxToken.balanceOf.callAsync(makerAddress);
- const finalTakerBalanceA = await noReturnErc20Token.balanceOf.callAsync(takerAddress);
- const finalTakerBalanceB = await erc20TokenB.balanceOf.callAsync(takerAddress);
- const finalTakerZrxBalance = await zrxToken.balanceOf.callAsync(takerAddress);
- const finalFeeRecipientZrxBalance = await zrxToken.balanceOf.callAsync(feeRecipientAddress);
-
- expect(finalMakerBalanceA).to.be.bignumber.equal(initialMakerBalanceA.minus(signedOrder.makerAssetAmount));
- expect(finalMakerBalanceB).to.be.bignumber.equal(initialMakerBalanceB.plus(signedOrder.takerAssetAmount));
- expect(finalTakerBalanceA).to.be.bignumber.equal(initialTakerBalanceA.plus(signedOrder.makerAssetAmount));
- expect(finalTakerBalanceB).to.be.bignumber.equal(initialTakerBalanceB.minus(signedOrder.takerAssetAmount));
- expect(finalMakerZrxBalance).to.be.bignumber.equal(initialMakerZrxBalance.minus(signedOrder.makerFee));
- expect(finalTakerZrxBalance).to.be.bignumber.equal(initialTakerZrxBalance.minus(signedOrder.takerFee));
- expect(finalFeeRecipientZrxBalance).to.be.bignumber.equal(
- initialFeeRecipientZrxBalance.plus(signedOrder.makerFee.plus(signedOrder.takerFee)),
- );
- });
- it('should transfer the correct amounts when makerAssetAmount > takerAssetAmount', async () => {
- signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetData: assetDataUtils.encodeERC20AssetData(noReturnErc20Token.address),
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(200), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18),
- });
-
- const initialMakerBalanceA = await noReturnErc20Token.balanceOf.callAsync(makerAddress);
- const initialMakerBalanceB = await erc20TokenB.balanceOf.callAsync(makerAddress);
- const initialMakerZrxBalance = await zrxToken.balanceOf.callAsync(makerAddress);
- const initialTakerBalanceA = await noReturnErc20Token.balanceOf.callAsync(takerAddress);
- const initialTakerBalanceB = await erc20TokenB.balanceOf.callAsync(takerAddress);
- const initialTakerZrxBalance = await zrxToken.balanceOf.callAsync(takerAddress);
- const initialFeeRecipientZrxBalance = await zrxToken.balanceOf.callAsync(feeRecipientAddress);
-
- await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress);
-
- const finalMakerBalanceA = await noReturnErc20Token.balanceOf.callAsync(makerAddress);
- const finalMakerBalanceB = await erc20TokenB.balanceOf.callAsync(makerAddress);
- const finalMakerZrxBalance = await zrxToken.balanceOf.callAsync(makerAddress);
- const finalTakerBalanceA = await noReturnErc20Token.balanceOf.callAsync(takerAddress);
- const finalTakerBalanceB = await erc20TokenB.balanceOf.callAsync(takerAddress);
- const finalTakerZrxBalance = await zrxToken.balanceOf.callAsync(takerAddress);
- const finalFeeRecipientZrxBalance = await zrxToken.balanceOf.callAsync(feeRecipientAddress);
-
- expect(finalMakerBalanceA).to.be.bignumber.equal(initialMakerBalanceA.minus(signedOrder.makerAssetAmount));
- expect(finalMakerBalanceB).to.be.bignumber.equal(initialMakerBalanceB.plus(signedOrder.takerAssetAmount));
- expect(finalTakerBalanceA).to.be.bignumber.equal(initialTakerBalanceA.plus(signedOrder.makerAssetAmount));
- expect(finalTakerBalanceB).to.be.bignumber.equal(initialTakerBalanceB.minus(signedOrder.takerAssetAmount));
- expect(finalMakerZrxBalance).to.be.bignumber.equal(initialMakerZrxBalance.minus(signedOrder.makerFee));
- expect(finalTakerZrxBalance).to.be.bignumber.equal(initialTakerZrxBalance.minus(signedOrder.takerFee));
- expect(finalFeeRecipientZrxBalance).to.be.bignumber.equal(
- initialFeeRecipientZrxBalance.plus(signedOrder.makerFee.plus(signedOrder.takerFee)),
- );
- });
- it('should transfer the correct amounts when makerAssetAmount < takerAssetAmount', async () => {
- signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetData: assetDataUtils.encodeERC20AssetData(noReturnErc20Token.address),
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(200), 18),
- });
-
- const initialMakerBalanceA = await noReturnErc20Token.balanceOf.callAsync(makerAddress);
- const initialMakerBalanceB = await erc20TokenB.balanceOf.callAsync(makerAddress);
- const initialMakerZrxBalance = await zrxToken.balanceOf.callAsync(makerAddress);
- const initialTakerBalanceA = await noReturnErc20Token.balanceOf.callAsync(takerAddress);
- const initialTakerBalanceB = await erc20TokenB.balanceOf.callAsync(takerAddress);
- const initialTakerZrxBalance = await zrxToken.balanceOf.callAsync(takerAddress);
- const initialFeeRecipientZrxBalance = await zrxToken.balanceOf.callAsync(feeRecipientAddress);
-
- await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress);
-
- const finalMakerBalanceA = await noReturnErc20Token.balanceOf.callAsync(makerAddress);
- const finalMakerBalanceB = await erc20TokenB.balanceOf.callAsync(makerAddress);
- const finalMakerZrxBalance = await zrxToken.balanceOf.callAsync(makerAddress);
- const finalTakerBalanceA = await noReturnErc20Token.balanceOf.callAsync(takerAddress);
- const finalTakerBalanceB = await erc20TokenB.balanceOf.callAsync(takerAddress);
- const finalTakerZrxBalance = await zrxToken.balanceOf.callAsync(takerAddress);
- const finalFeeRecipientZrxBalance = await zrxToken.balanceOf.callAsync(feeRecipientAddress);
-
- expect(finalMakerBalanceA).to.be.bignumber.equal(initialMakerBalanceA.minus(signedOrder.makerAssetAmount));
- expect(finalMakerBalanceB).to.be.bignumber.equal(initialMakerBalanceB.plus(signedOrder.takerAssetAmount));
- expect(finalTakerBalanceA).to.be.bignumber.equal(initialTakerBalanceA.plus(signedOrder.makerAssetAmount));
- expect(finalTakerBalanceB).to.be.bignumber.equal(initialTakerBalanceB.minus(signedOrder.takerAssetAmount));
- expect(finalMakerZrxBalance).to.be.bignumber.equal(initialMakerZrxBalance.minus(signedOrder.makerFee));
- expect(finalTakerZrxBalance).to.be.bignumber.equal(initialTakerZrxBalance.minus(signedOrder.takerFee));
- expect(finalFeeRecipientZrxBalance).to.be.bignumber.equal(
- initialFeeRecipientZrxBalance.plus(signedOrder.makerFee.plus(signedOrder.takerFee)),
- );
- });
- });
-
- describe('cancelOrder', () => {
- beforeEach(async () => {
- erc20Balances = await erc20Wrapper.getBalancesAsync();
- signedOrder = await orderFactory.newSignedOrderAsync();
- });
-
- it('should throw if not sent by maker', async () => {
- return expectTransactionFailedAsync(
- exchangeWrapper.cancelOrderAsync(signedOrder, takerAddress),
- RevertReason.InvalidMaker,
- );
- });
-
- it('should throw if makerAssetAmount is 0', async () => {
- signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetAmount: new BigNumber(0),
- });
-
- return expectTransactionFailedAsync(
- exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress),
- RevertReason.OrderUnfillable,
- );
- });
-
- it('should throw if takerAssetAmount is 0', async () => {
- signedOrder = await orderFactory.newSignedOrderAsync({
- takerAssetAmount: new BigNumber(0),
- });
-
- return expectTransactionFailedAsync(
- exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress),
- RevertReason.OrderUnfillable,
- );
- });
-
- it('should be able to cancel a full order', async () => {
- await exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress);
- return expectTransactionFailedAsync(
- exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, {
- takerAssetFillAmount: signedOrder.takerAssetAmount.div(2),
- }),
- RevertReason.OrderUnfillable,
- );
- });
-
- it('should log 1 event with correct arguments', async () => {
- const res = await exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress);
- expect(res.logs).to.have.length(1);
-
- const log = res.logs[0] as LogWithDecodedArgs<ExchangeCancelEventArgs>;
- const logArgs = log.args;
-
- expect(signedOrder.makerAddress).to.be.equal(logArgs.makerAddress);
- expect(signedOrder.makerAddress).to.be.equal(logArgs.senderAddress);
- expect(signedOrder.feeRecipientAddress).to.be.equal(logArgs.feeRecipientAddress);
- expect(signedOrder.makerAssetData).to.be.equal(logArgs.makerAssetData);
- expect(signedOrder.takerAssetData).to.be.equal(logArgs.takerAssetData);
- expect(orderHashUtils.getOrderHashHex(signedOrder)).to.be.equal(logArgs.orderHash);
- });
-
- it('should throw if already cancelled', async () => {
- await exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress);
- return expectTransactionFailedAsync(
- exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress),
- RevertReason.OrderUnfillable,
- );
- });
-
- it('should throw if order is expired', async () => {
- const currentTimestamp = await getLatestBlockTimestampAsync();
- signedOrder = await orderFactory.newSignedOrderAsync({
- expirationTimeSeconds: new BigNumber(currentTimestamp).sub(10),
- });
- return expectTransactionFailedAsync(
- exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress),
- RevertReason.OrderUnfillable,
- );
- });
-
- it('should throw if rounding error is greater than 0.1%', async () => {
- signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetAmount: new BigNumber(1001),
- takerAssetAmount: new BigNumber(3),
- });
-
- const fillTakerAssetAmount1 = new BigNumber(2);
- await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, {
- takerAssetFillAmount: fillTakerAssetAmount1,
- });
-
- const fillTakerAssetAmount2 = new BigNumber(1);
- return expectTransactionFailedAsync(
- exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, {
- takerAssetFillAmount: fillTakerAssetAmount2,
- }),
- RevertReason.RoundingError,
- );
- });
- });
-
- describe('cancelOrdersUpTo', () => {
- it('should fail to set orderEpoch less than current orderEpoch', async () => {
- const orderEpoch = new BigNumber(1);
- await exchangeWrapper.cancelOrdersUpToAsync(orderEpoch, makerAddress);
- const lesserOrderEpoch = new BigNumber(0);
- return expectTransactionFailedAsync(
- exchangeWrapper.cancelOrdersUpToAsync(lesserOrderEpoch, makerAddress),
- RevertReason.InvalidNewOrderEpoch,
- );
- });
-
- it('should fail to set orderEpoch equal to existing orderEpoch', async () => {
- const orderEpoch = new BigNumber(1);
- await exchangeWrapper.cancelOrdersUpToAsync(orderEpoch, makerAddress);
- return expectTransactionFailedAsync(
- exchangeWrapper.cancelOrdersUpToAsync(orderEpoch, makerAddress),
- RevertReason.InvalidNewOrderEpoch,
- );
- });
-
- it('should cancel only orders with a orderEpoch less than existing orderEpoch', async () => {
- // Cancel all transactions with a orderEpoch less than 1
- const orderEpoch = new BigNumber(1);
- await exchangeWrapper.cancelOrdersUpToAsync(orderEpoch, makerAddress);
-
- // Create 3 orders with orderEpoch values: 0,1,2,3
- // Since we cancelled with orderEpoch=1, orders with orderEpoch<=1 will not be processed
- erc20Balances = await erc20Wrapper.getBalancesAsync();
- const signedOrders = [
- await orderFactory.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(9), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(9), 18),
- salt: new BigNumber(0),
- }),
- await orderFactory.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(79), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(79), 18),
- salt: new BigNumber(1),
- }),
- await orderFactory.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(979), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(979), 18),
- salt: new BigNumber(2),
- }),
- await orderFactory.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(7979), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(7979), 18),
- salt: new BigNumber(3),
- }),
- ];
- await exchangeWrapper.batchFillOrdersNoThrowAsync(signedOrders, takerAddress, {
- // 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,
- });
-
- const newBalances = await erc20Wrapper.getBalancesAsync();
- const fillMakerAssetAmount = signedOrders[2].makerAssetAmount.add(signedOrders[3].makerAssetAmount);
- const fillTakerAssetAmount = signedOrders[2].takerAssetAmount.add(signedOrders[3].takerAssetAmount);
- const makerFee = signedOrders[2].makerFee.add(signedOrders[3].makerFee);
- const takerFee = signedOrders[2].takerFee.add(signedOrders[3].takerFee);
- expect(newBalances[makerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultMakerAssetAddress].minus(fillMakerAssetAmount),
- );
- expect(newBalances[makerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultTakerAssetAddress].add(fillTakerAssetAmount),
- );
- expect(newBalances[makerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][zrxToken.address].minus(makerFee),
- );
- expect(newBalances[takerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultTakerAssetAddress].minus(fillTakerAssetAmount),
- );
- expect(newBalances[takerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultMakerAssetAddress].add(fillMakerAssetAmount),
- );
- expect(newBalances[takerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[takerAddress][zrxToken.address].minus(takerFee),
- );
- expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[feeRecipientAddress][zrxToken.address].add(makerFee.add(takerFee)),
- );
- });
- });
-
- describe('Testing Exchange of ERC721 Tokens', () => {
- it('should throw when maker does not own the token with id makerAssetId', async () => {
- // Construct Exchange parameters
- const makerAssetId = erc721TakerAssetIds[0];
- const takerAssetId = erc721TakerAssetIds[1];
- signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetAmount: new BigNumber(1),
- takerAssetAmount: new BigNumber(1),
- makerAssetData: assetDataUtils.encodeERC721AssetData(erc721Token.address, makerAssetId),
- takerAssetData: assetDataUtils.encodeERC721AssetData(erc721Token.address, takerAssetId),
- });
- // Verify pre-conditions
- const initialOwnerMakerAsset = await erc721Token.ownerOf.callAsync(makerAssetId);
- expect(initialOwnerMakerAsset).to.be.bignumber.not.equal(makerAddress);
- const initialOwnerTakerAsset = await erc721Token.ownerOf.callAsync(takerAssetId);
- expect(initialOwnerTakerAsset).to.be.bignumber.equal(takerAddress);
- // Call Exchange
- const takerAssetFillAmount = signedOrder.takerAssetAmount;
- return expectTransactionFailedAsync(
- exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount }),
- RevertReason.TransferFailed,
- );
- });
-
- it('should throw when taker does not own the token with id takerAssetId', async () => {
- // Construct Exchange parameters
- const makerAssetId = erc721MakerAssetIds[0];
- const takerAssetId = erc721MakerAssetIds[1];
- signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetAmount: new BigNumber(1),
- takerAssetAmount: new BigNumber(1),
- makerAssetData: assetDataUtils.encodeERC721AssetData(erc721Token.address, makerAssetId),
- takerAssetData: assetDataUtils.encodeERC721AssetData(erc721Token.address, takerAssetId),
- });
- // Verify pre-conditions
- const initialOwnerMakerAsset = await erc721Token.ownerOf.callAsync(makerAssetId);
- expect(initialOwnerMakerAsset).to.be.bignumber.equal(makerAddress);
- const initialOwnerTakerAsset = await erc721Token.ownerOf.callAsync(takerAssetId);
- expect(initialOwnerTakerAsset).to.be.bignumber.not.equal(takerAddress);
- // Call Exchange
- const takerAssetFillAmount = signedOrder.takerAssetAmount;
- return expectTransactionFailedAsync(
- exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount }),
- RevertReason.TransferFailed,
- );
- });
-
- it('should throw when makerAssetAmount is greater than 1', async () => {
- // Construct Exchange parameters
- const makerAssetId = erc721MakerAssetIds[0];
- const takerAssetId = erc721TakerAssetIds[0];
- signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetAmount: new BigNumber(2),
- takerAssetAmount: new BigNumber(1),
- makerAssetData: assetDataUtils.encodeERC721AssetData(erc721Token.address, makerAssetId),
- takerAssetData: assetDataUtils.encodeERC721AssetData(erc721Token.address, takerAssetId),
- });
- // Verify pre-conditions
- const initialOwnerMakerAsset = await erc721Token.ownerOf.callAsync(makerAssetId);
- expect(initialOwnerMakerAsset).to.be.bignumber.equal(makerAddress);
- const initialOwnerTakerAsset = await erc721Token.ownerOf.callAsync(takerAssetId);
- expect(initialOwnerTakerAsset).to.be.bignumber.equal(takerAddress);
- // Call Exchange
- const takerAssetFillAmount = signedOrder.takerAssetAmount;
- return expectTransactionFailedAsync(
- exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount }),
- RevertReason.InvalidAmount,
- );
- });
-
- it('should throw when takerAssetAmount is greater than 1', async () => {
- // Construct Exchange parameters
- const makerAssetId = erc721MakerAssetIds[0];
- const takerAssetId = erc721TakerAssetIds[0];
- signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetAmount: new BigNumber(1),
- takerAssetAmount: new BigNumber(500),
- makerAssetData: assetDataUtils.encodeERC721AssetData(erc721Token.address, makerAssetId),
- takerAssetData: assetDataUtils.encodeERC721AssetData(erc721Token.address, takerAssetId),
- });
- // Verify pre-conditions
- const initialOwnerMakerAsset = await erc721Token.ownerOf.callAsync(makerAssetId);
- expect(initialOwnerMakerAsset).to.be.bignumber.equal(makerAddress);
- const initialOwnerTakerAsset = await erc721Token.ownerOf.callAsync(takerAssetId);
- expect(initialOwnerTakerAsset).to.be.bignumber.equal(takerAddress);
- // Call Exchange
- const takerAssetFillAmount = signedOrder.takerAssetAmount;
- return expectTransactionFailedAsync(
- exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount }),
- RevertReason.InvalidAmount,
- );
- });
-
- it('should throw on partial fill', async () => {
- // Construct Exchange parameters
- const makerAssetId = erc721MakerAssetIds[0];
- signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetAmount: new BigNumber(1),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18),
- makerAssetData: assetDataUtils.encodeERC721AssetData(erc721Token.address, makerAssetId),
- takerAssetData: assetDataUtils.encodeERC20AssetData(defaultTakerAssetAddress),
- });
- // Call Exchange
- const takerAssetFillAmount = signedOrder.takerAssetAmount.div(2);
- return expectTransactionFailedAsync(
- exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount }),
- RevertReason.RoundingError,
- );
- });
- });
-
- describe('Testing exchange of multiple assets', () => {
- it('should allow multiple assets to be exchanged for a single asset', async () => {
- const makerAmounts = [new BigNumber(10), new BigNumber(20)];
- const makerNestedAssetData = [
- assetDataUtils.encodeERC20AssetData(erc20TokenA.address),
- assetDataUtils.encodeERC20AssetData(erc20TokenB.address),
- ];
- const makerAssetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(
- makerAmounts,
- makerNestedAssetData,
- );
- const makerAssetAmount = new BigNumber(1);
- const takerAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address);
- const takerAssetAmount = new BigNumber(10);
- signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetData,
- takerAssetData,
- makerAssetAmount,
- takerAssetAmount,
- makerFee: constants.ZERO_AMOUNT,
- takerFee: constants.ZERO_AMOUNT,
- });
-
- const initialMakerBalanceA = await erc20TokenA.balanceOf.callAsync(makerAddress);
- const initialMakerBalanceB = await erc20TokenB.balanceOf.callAsync(makerAddress);
- const initialMakerZrxBalance = await zrxToken.balanceOf.callAsync(makerAddress);
- const initialTakerBalanceA = await erc20TokenA.balanceOf.callAsync(takerAddress);
- const initialTakerBalanceB = await erc20TokenB.balanceOf.callAsync(takerAddress);
- const initialTakerZrxBalance = await zrxToken.balanceOf.callAsync(takerAddress);
-
- await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress);
-
- const finalMakerBalanceA = await erc20TokenA.balanceOf.callAsync(makerAddress);
- const finalMakerBalanceB = await erc20TokenB.balanceOf.callAsync(makerAddress);
- const finalMakerZrxBalance = await zrxToken.balanceOf.callAsync(makerAddress);
- const finalTakerBalanceA = await erc20TokenA.balanceOf.callAsync(takerAddress);
- const finalTakerBalanceB = await erc20TokenB.balanceOf.callAsync(takerAddress);
- const finalTakerZrxBalance = await zrxToken.balanceOf.callAsync(takerAddress);
-
- expect(finalMakerBalanceA).to.be.bignumber.equal(
- initialMakerBalanceA.minus(makerAmounts[0].times(makerAssetAmount)),
- );
- expect(finalMakerBalanceB).to.be.bignumber.equal(
- initialMakerBalanceB.minus(makerAmounts[1].times(makerAssetAmount)),
- );
- expect(finalMakerZrxBalance).to.be.bignumber.equal(initialMakerZrxBalance.plus(takerAssetAmount));
- expect(finalTakerBalanceA).to.be.bignumber.equal(
- initialTakerBalanceA.plus(makerAmounts[0].times(makerAssetAmount)),
- );
- expect(finalTakerBalanceB).to.be.bignumber.equal(
- initialTakerBalanceB.plus(makerAmounts[1].times(makerAssetAmount)),
- );
- expect(finalTakerZrxBalance).to.be.bignumber.equal(initialTakerZrxBalance.minus(takerAssetAmount));
- });
- it('should allow multiple assets to be exchanged for multiple assets', async () => {
- const makerAmounts = [new BigNumber(10), new BigNumber(20)];
- const makerNestedAssetData = [
- assetDataUtils.encodeERC20AssetData(erc20TokenA.address),
- assetDataUtils.encodeERC20AssetData(erc20TokenB.address),
- ];
- const makerAssetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(
- makerAmounts,
- makerNestedAssetData,
- );
- const makerAssetAmount = new BigNumber(1);
- const takerAmounts = [new BigNumber(10), new BigNumber(1)];
- const takerAssetId = erc721TakerAssetIds[0];
- const takerNestedAssetData = [
- assetDataUtils.encodeERC20AssetData(zrxToken.address),
- assetDataUtils.encodeERC721AssetData(erc721Token.address, takerAssetId),
- ];
- const takerAssetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(
- takerAmounts,
- takerNestedAssetData,
- );
- const takerAssetAmount = new BigNumber(1);
- signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetData,
- takerAssetData,
- makerAssetAmount,
- takerAssetAmount,
- makerFee: constants.ZERO_AMOUNT,
- takerFee: constants.ZERO_AMOUNT,
- });
-
- const initialMakerBalanceA = await erc20TokenA.balanceOf.callAsync(makerAddress);
- const initialMakerBalanceB = await erc20TokenB.balanceOf.callAsync(makerAddress);
- const initialMakerZrxBalance = await zrxToken.balanceOf.callAsync(makerAddress);
- const initialTakerBalanceA = await erc20TokenA.balanceOf.callAsync(takerAddress);
- const initialTakerBalanceB = await erc20TokenB.balanceOf.callAsync(takerAddress);
- const initialTakerZrxBalance = await zrxToken.balanceOf.callAsync(takerAddress);
- const initialOwnerTakerAsset = await erc721Token.ownerOf.callAsync(takerAssetId);
- expect(initialOwnerTakerAsset).to.be.bignumber.equal(takerAddress);
-
- await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress);
-
- const finalMakerBalanceA = await erc20TokenA.balanceOf.callAsync(makerAddress);
- const finalMakerBalanceB = await erc20TokenB.balanceOf.callAsync(makerAddress);
- const finalMakerZrxBalance = await zrxToken.balanceOf.callAsync(makerAddress);
- const finalTakerBalanceA = await erc20TokenA.balanceOf.callAsync(takerAddress);
- const finalTakerBalanceB = await erc20TokenB.balanceOf.callAsync(takerAddress);
- const finalTakerZrxBalance = await zrxToken.balanceOf.callAsync(takerAddress);
- const finalOwnerTakerAsset = await erc721Token.ownerOf.callAsync(takerAssetId);
-
- expect(finalMakerBalanceA).to.be.bignumber.equal(
- initialMakerBalanceA.minus(makerAmounts[0].times(makerAssetAmount)),
- );
- expect(finalMakerBalanceB).to.be.bignumber.equal(
- initialMakerBalanceB.minus(makerAmounts[1].times(makerAssetAmount)),
- );
- expect(finalMakerZrxBalance).to.be.bignumber.equal(
- initialMakerZrxBalance.plus(takerAmounts[0].times(takerAssetAmount)),
- );
- expect(finalTakerBalanceA).to.be.bignumber.equal(
- initialTakerBalanceA.plus(makerAmounts[0].times(makerAssetAmount)),
- );
- expect(finalTakerBalanceB).to.be.bignumber.equal(
- initialTakerBalanceB.plus(makerAmounts[1].times(makerAssetAmount)),
- );
- expect(finalTakerZrxBalance).to.be.bignumber.equal(
- initialTakerZrxBalance.minus(takerAmounts[0].times(takerAssetAmount)),
- );
- expect(finalOwnerTakerAsset).to.be.equal(makerAddress);
- });
- it('should allow an order selling multiple assets to be partially filled', async () => {
- const makerAmounts = [new BigNumber(10), new BigNumber(20)];
- const makerNestedAssetData = [
- assetDataUtils.encodeERC20AssetData(erc20TokenA.address),
- assetDataUtils.encodeERC20AssetData(erc20TokenB.address),
- ];
- const makerAssetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(
- makerAmounts,
- makerNestedAssetData,
- );
- const makerAssetAmount = new BigNumber(30);
- const takerAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address);
- const takerAssetAmount = new BigNumber(10);
- signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetData,
- takerAssetData,
- makerAssetAmount,
- takerAssetAmount,
- makerFee: constants.ZERO_AMOUNT,
- takerFee: constants.ZERO_AMOUNT,
- });
-
- const initialMakerBalanceA = await erc20TokenA.balanceOf.callAsync(makerAddress);
- const initialMakerBalanceB = await erc20TokenB.balanceOf.callAsync(makerAddress);
- const initialMakerZrxBalance = await zrxToken.balanceOf.callAsync(makerAddress);
- const initialTakerBalanceA = await erc20TokenA.balanceOf.callAsync(takerAddress);
- const initialTakerBalanceB = await erc20TokenB.balanceOf.callAsync(takerAddress);
- const initialTakerZrxBalance = await zrxToken.balanceOf.callAsync(takerAddress);
-
- const takerAssetFillAmount = takerAssetAmount.dividedToIntegerBy(2);
- await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, {
- takerAssetFillAmount,
- });
-
- const finalMakerBalanceA = await erc20TokenA.balanceOf.callAsync(makerAddress);
- const finalMakerBalanceB = await erc20TokenB.balanceOf.callAsync(makerAddress);
- const finalMakerZrxBalance = await zrxToken.balanceOf.callAsync(makerAddress);
- const finalTakerBalanceA = await erc20TokenA.balanceOf.callAsync(takerAddress);
- const finalTakerBalanceB = await erc20TokenB.balanceOf.callAsync(takerAddress);
- const finalTakerZrxBalance = await zrxToken.balanceOf.callAsync(takerAddress);
-
- expect(finalMakerBalanceA).to.be.bignumber.equal(
- initialMakerBalanceA.minus(
- makerAmounts[0].times(
- makerAssetAmount.times(takerAssetFillAmount).dividedToIntegerBy(takerAssetAmount),
- ),
- ),
- );
- expect(finalMakerBalanceB).to.be.bignumber.equal(
- initialMakerBalanceB.minus(
- makerAmounts[1].times(
- makerAssetAmount.times(takerAssetFillAmount).dividedToIntegerBy(takerAssetAmount),
- ),
- ),
- );
- expect(finalMakerZrxBalance).to.be.bignumber.equal(
- initialMakerZrxBalance.plus(
- takerAssetAmount.times(takerAssetFillAmount).dividedToIntegerBy(takerAssetAmount),
- ),
- );
- expect(finalTakerBalanceA).to.be.bignumber.equal(
- initialTakerBalanceA.plus(
- makerAmounts[0].times(
- makerAssetAmount.times(takerAssetFillAmount).dividedToIntegerBy(takerAssetAmount),
- ),
- ),
- );
- expect(finalTakerBalanceB).to.be.bignumber.equal(
- initialTakerBalanceB.plus(
- makerAmounts[1].times(
- makerAssetAmount.times(takerAssetFillAmount).dividedToIntegerBy(takerAssetAmount),
- ),
- ),
- );
- expect(finalTakerZrxBalance).to.be.bignumber.equal(
- initialTakerZrxBalance.minus(
- takerAssetAmount.times(takerAssetFillAmount).dividedToIntegerBy(takerAssetAmount),
- ),
- );
- });
- it('should allow an order buying multiple assets to be partially filled', async () => {
- const takerAmounts = [new BigNumber(10), new BigNumber(20)];
- const takerNestedAssetData = [
- assetDataUtils.encodeERC20AssetData(erc20TokenA.address),
- assetDataUtils.encodeERC20AssetData(erc20TokenB.address),
- ];
- const takerAssetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(
- takerAmounts,
- takerNestedAssetData,
- );
- const takerAssetAmount = new BigNumber(30);
- const makerAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address);
- const makerAssetAmount = new BigNumber(10);
- signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetData,
- takerAssetData,
- makerAssetAmount,
- takerAssetAmount,
- makerFee: constants.ZERO_AMOUNT,
- takerFee: constants.ZERO_AMOUNT,
- });
-
- const initialMakerBalanceA = await erc20TokenA.balanceOf.callAsync(makerAddress);
- const initialMakerBalanceB = await erc20TokenB.balanceOf.callAsync(makerAddress);
- const initialMakerZrxBalance = await zrxToken.balanceOf.callAsync(makerAddress);
- const initialTakerBalanceA = await erc20TokenA.balanceOf.callAsync(takerAddress);
- const initialTakerBalanceB = await erc20TokenB.balanceOf.callAsync(takerAddress);
- const initialTakerZrxBalance = await zrxToken.balanceOf.callAsync(takerAddress);
-
- const takerAssetFillAmount = takerAssetAmount.dividedToIntegerBy(2);
- await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, {
- takerAssetFillAmount,
- });
-
- const finalMakerBalanceA = await erc20TokenA.balanceOf.callAsync(makerAddress);
- const finalMakerBalanceB = await erc20TokenB.balanceOf.callAsync(makerAddress);
- const finalMakerZrxBalance = await zrxToken.balanceOf.callAsync(makerAddress);
- const finalTakerBalanceA = await erc20TokenA.balanceOf.callAsync(takerAddress);
- const finalTakerBalanceB = await erc20TokenB.balanceOf.callAsync(takerAddress);
- const finalTakerZrxBalance = await zrxToken.balanceOf.callAsync(takerAddress);
-
- expect(finalMakerBalanceA).to.be.bignumber.equal(
- initialMakerBalanceA.plus(
- takerAmounts[0].times(
- takerAssetAmount.times(takerAssetFillAmount).dividedToIntegerBy(takerAssetAmount),
- ),
- ),
- );
- expect(finalMakerBalanceB).to.be.bignumber.equal(
- initialMakerBalanceB.plus(
- takerAmounts[1].times(
- takerAssetAmount.times(takerAssetFillAmount).dividedToIntegerBy(takerAssetAmount),
- ),
- ),
- );
- expect(finalMakerZrxBalance).to.be.bignumber.equal(
- initialMakerZrxBalance.minus(
- makerAssetAmount.times(takerAssetFillAmount).dividedToIntegerBy(takerAssetAmount),
- ),
- );
- expect(finalTakerBalanceA).to.be.bignumber.equal(
- initialTakerBalanceA.minus(
- takerAmounts[0].times(
- takerAssetAmount.times(takerAssetFillAmount).dividedToIntegerBy(takerAssetAmount),
- ),
- ),
- );
- expect(finalTakerBalanceB).to.be.bignumber.equal(
- initialTakerBalanceB.minus(
- takerAmounts[1].times(
- takerAssetAmount.times(takerAssetFillAmount).dividedToIntegerBy(takerAssetAmount),
- ),
- ),
- );
- expect(finalTakerZrxBalance).to.be.bignumber.equal(
- initialTakerZrxBalance.plus(
- makerAssetAmount.times(takerAssetFillAmount).dividedToIntegerBy(takerAssetAmount),
- ),
- );
- });
- });
-
- describe('getOrderInfo', () => {
- beforeEach(async () => {
- signedOrder = await orderFactory.newSignedOrderAsync();
- });
- it('should return the correct orderInfo for an unfilled valid order', async () => {
- const orderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrder);
- const expectedOrderHash = orderHashUtils.getOrderHashHex(signedOrder);
- const expectedTakerAssetFilledAmount = new BigNumber(0);
- const expectedOrderStatus = OrderStatus.FILLABLE;
- expect(orderInfo.orderHash).to.be.equal(expectedOrderHash);
- expect(orderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(expectedTakerAssetFilledAmount);
- expect(orderInfo.orderStatus).to.equal(expectedOrderStatus);
- });
- it('should return the correct orderInfo for a fully filled order', async () => {
- await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress);
- const orderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrder);
- const expectedOrderHash = orderHashUtils.getOrderHashHex(signedOrder);
- const expectedTakerAssetFilledAmount = signedOrder.takerAssetAmount;
- const expectedOrderStatus = OrderStatus.FULLY_FILLED;
- expect(orderInfo.orderHash).to.be.equal(expectedOrderHash);
- expect(orderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(expectedTakerAssetFilledAmount);
- expect(orderInfo.orderStatus).to.equal(expectedOrderStatus);
- });
- it('should return the correct orderInfo for a partially filled order', async () => {
- const takerAssetFillAmount = signedOrder.takerAssetAmount.div(2);
- await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount });
- const orderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrder);
- const expectedOrderHash = orderHashUtils.getOrderHashHex(signedOrder);
- const expectedTakerAssetFilledAmount = takerAssetFillAmount;
- const expectedOrderStatus = OrderStatus.FILLABLE;
- expect(orderInfo.orderHash).to.be.equal(expectedOrderHash);
- expect(orderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(expectedTakerAssetFilledAmount);
- expect(orderInfo.orderStatus).to.equal(expectedOrderStatus);
- });
- it('should return the correct orderInfo for a cancelled and unfilled order', async () => {
- await exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress);
- const orderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrder);
- const expectedOrderHash = orderHashUtils.getOrderHashHex(signedOrder);
- const expectedTakerAssetFilledAmount = new BigNumber(0);
- const expectedOrderStatus = OrderStatus.CANCELLED;
- expect(orderInfo.orderHash).to.be.equal(expectedOrderHash);
- expect(orderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(expectedTakerAssetFilledAmount);
- expect(orderInfo.orderStatus).to.equal(expectedOrderStatus);
- });
- it('should return the correct orderInfo for a cancelled and partially filled order', async () => {
- const takerAssetFillAmount = signedOrder.takerAssetAmount.div(2);
- await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount });
- await exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress);
- const orderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrder);
- const expectedOrderHash = orderHashUtils.getOrderHashHex(signedOrder);
- const expectedTakerAssetFilledAmount = takerAssetFillAmount;
- const expectedOrderStatus = OrderStatus.CANCELLED;
- expect(orderInfo.orderHash).to.be.equal(expectedOrderHash);
- expect(orderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(expectedTakerAssetFilledAmount);
- expect(orderInfo.orderStatus).to.equal(expectedOrderStatus);
- });
- it('should return the correct orderInfo for an expired and unfilled order', async () => {
- const currentTimestamp = await getLatestBlockTimestampAsync();
- const timeUntilExpiration = signedOrder.expirationTimeSeconds.minus(currentTimestamp).toNumber();
- await increaseTimeAndMineBlockAsync(timeUntilExpiration);
- const orderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrder);
- const expectedOrderHash = orderHashUtils.getOrderHashHex(signedOrder);
- const expectedTakerAssetFilledAmount = new BigNumber(0);
- const expectedOrderStatus = OrderStatus.EXPIRED;
- expect(orderInfo.orderHash).to.be.equal(expectedOrderHash);
- expect(orderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(expectedTakerAssetFilledAmount);
- expect(orderInfo.orderStatus).to.equal(expectedOrderStatus);
- });
- it('should return the correct orderInfo for an expired and partially filled order', async () => {
- const takerAssetFillAmount = signedOrder.takerAssetAmount.div(2);
- await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount });
- const currentTimestamp = await getLatestBlockTimestampAsync();
- const timeUntilExpiration = signedOrder.expirationTimeSeconds.minus(currentTimestamp).toNumber();
- await increaseTimeAndMineBlockAsync(timeUntilExpiration);
- const orderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrder);
- const expectedOrderHash = orderHashUtils.getOrderHashHex(signedOrder);
- const expectedTakerAssetFilledAmount = takerAssetFillAmount;
- const expectedOrderStatus = OrderStatus.EXPIRED;
- expect(orderInfo.orderHash).to.be.equal(expectedOrderHash);
- expect(orderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(expectedTakerAssetFilledAmount);
- expect(orderInfo.orderStatus).to.equal(expectedOrderStatus);
- });
- it('should return the correct orderInfo for an expired and fully filled order', async () => {
- await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress);
- const currentTimestamp = await getLatestBlockTimestampAsync();
- const timeUntilExpiration = signedOrder.expirationTimeSeconds.minus(currentTimestamp).toNumber();
- await increaseTimeAndMineBlockAsync(timeUntilExpiration);
- const orderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrder);
- const expectedOrderHash = orderHashUtils.getOrderHashHex(signedOrder);
- const expectedTakerAssetFilledAmount = signedOrder.takerAssetAmount;
- // FULLY_FILLED takes precedence over EXPIRED
- const expectedOrderStatus = OrderStatus.FULLY_FILLED;
- expect(orderInfo.orderHash).to.be.equal(expectedOrderHash);
- expect(orderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(expectedTakerAssetFilledAmount);
- expect(orderInfo.orderStatus).to.equal(expectedOrderStatus);
- });
- it('should return the correct orderInfo for an order with a makerAssetAmount of 0', async () => {
- signedOrder = await orderFactory.newSignedOrderAsync({ makerAssetAmount: new BigNumber(0) });
- const orderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrder);
- const expectedOrderHash = orderHashUtils.getOrderHashHex(signedOrder);
- const expectedTakerAssetFilledAmount = new BigNumber(0);
- const expectedOrderStatus = OrderStatus.INVALID_MAKER_ASSET_AMOUNT;
- expect(orderInfo.orderHash).to.be.equal(expectedOrderHash);
- expect(orderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(expectedTakerAssetFilledAmount);
- expect(orderInfo.orderStatus).to.equal(expectedOrderStatus);
- });
- it('should return the correct orderInfo for an order with a takerAssetAmount of 0', async () => {
- signedOrder = await orderFactory.newSignedOrderAsync({ takerAssetAmount: new BigNumber(0) });
- const orderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrder);
- const expectedOrderHash = orderHashUtils.getOrderHashHex(signedOrder);
- const expectedTakerAssetFilledAmount = new BigNumber(0);
- const expectedOrderStatus = OrderStatus.INVALID_TAKER_ASSET_AMOUNT;
- expect(orderInfo.orderHash).to.be.equal(expectedOrderHash);
- expect(orderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(expectedTakerAssetFilledAmount);
- expect(orderInfo.orderStatus).to.equal(expectedOrderStatus);
- });
- });
-});
-// tslint:disable:max-file-line-count
-// tslint:enable:no-unnecessary-type-assertion
diff --git a/packages/contracts/test/exchange/dispatcher.ts b/packages/contracts/test/exchange/dispatcher.ts
deleted file mode 100644
index 3d3aa42c2..000000000
--- a/packages/contracts/test/exchange/dispatcher.ts
+++ /dev/null
@@ -1,280 +0,0 @@
-import { BlockchainLifecycle } from '@0x/dev-utils';
-import { assetDataUtils } from '@0x/order-utils';
-import { AssetProxyId, RevertReason } from '@0x/types';
-import { BigNumber } from '@0x/utils';
-import * as chai from 'chai';
-import { LogWithDecodedArgs } from 'ethereum-types';
-import * as _ from 'lodash';
-
-import { DummyERC20TokenContract } from '../../generated-wrappers/dummy_erc20_token';
-import { ERC20ProxyContract } from '../../generated-wrappers/erc20_proxy';
-import { ERC721ProxyContract } from '../../generated-wrappers/erc721_proxy';
-import {
- TestAssetProxyDispatcherAssetProxyRegisteredEventArgs,
- TestAssetProxyDispatcherContract,
-} from '../../generated-wrappers/test_asset_proxy_dispatcher';
-import { artifacts } from '../../src/artifacts';
-import { expectTransactionFailedAsync } from '../utils/assertions';
-import { chaiSetup } from '../utils/chai_setup';
-import { constants } from '../utils/constants';
-import { ERC20Wrapper } from '../utils/erc20_wrapper';
-import { ERC721Wrapper } from '../utils/erc721_wrapper';
-import { LogDecoder } from '../utils/log_decoder';
-import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper';
-
-chaiSetup.configure();
-const expect = chai.expect;
-const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
-// tslint:disable:no-unnecessary-type-assertion
-describe('AssetProxyDispatcher', () => {
- let owner: string;
- let notOwner: string;
- let makerAddress: string;
- let takerAddress: string;
-
- let zrxToken: DummyERC20TokenContract;
- let erc20Proxy: ERC20ProxyContract;
- let erc721Proxy: ERC721ProxyContract;
- let assetProxyDispatcher: TestAssetProxyDispatcherContract;
-
- let erc20Wrapper: ERC20Wrapper;
- let erc721Wrapper: ERC721Wrapper;
-
- before(async () => {
- await blockchainLifecycle.startAsync();
- });
- after(async () => {
- await blockchainLifecycle.revertAsync();
- });
- before(async () => {
- // Setup accounts & addresses
- const accounts = await web3Wrapper.getAvailableAddressesAsync();
- const usedAddresses = ([owner, notOwner, makerAddress, takerAddress] = _.slice(accounts, 0, 4));
-
- erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner);
- erc721Wrapper = new ERC721Wrapper(provider, usedAddresses, owner);
-
- const numDummyErc20ToDeploy = 1;
- [zrxToken] = await erc20Wrapper.deployDummyTokensAsync(numDummyErc20ToDeploy, constants.DUMMY_TOKEN_DECIMALS);
- erc20Proxy = await erc20Wrapper.deployProxyAsync();
- await erc20Wrapper.setBalancesAndAllowancesAsync();
-
- erc721Proxy = await erc721Wrapper.deployProxyAsync();
-
- assetProxyDispatcher = await TestAssetProxyDispatcherContract.deployFrom0xArtifactAsync(
- artifacts.TestAssetProxyDispatcher,
- provider,
- txDefaults,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc20Proxy.addAuthorizedAddress.sendTransactionAsync(assetProxyDispatcher.address, {
- from: owner,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc721Proxy.addAuthorizedAddress.sendTransactionAsync(assetProxyDispatcher.address, {
- from: owner,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- });
- beforeEach(async () => {
- await blockchainLifecycle.startAsync();
- });
- afterEach(async () => {
- await blockchainLifecycle.revertAsync();
- });
- describe('registerAssetProxy', () => {
- it('should record proxy upon registration', async () => {
- await web3Wrapper.awaitTransactionSuccessAsync(
- await assetProxyDispatcher.registerAssetProxy.sendTransactionAsync(erc20Proxy.address, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const proxyAddress = await assetProxyDispatcher.getAssetProxy.callAsync(AssetProxyId.ERC20);
- expect(proxyAddress).to.be.equal(erc20Proxy.address);
- });
-
- it('should be able to record multiple proxies', async () => {
- // Record first proxy
- await web3Wrapper.awaitTransactionSuccessAsync(
- await assetProxyDispatcher.registerAssetProxy.sendTransactionAsync(erc20Proxy.address, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- let proxyAddress = await assetProxyDispatcher.getAssetProxy.callAsync(AssetProxyId.ERC20);
- expect(proxyAddress).to.be.equal(erc20Proxy.address);
- // Record another proxy
- await web3Wrapper.awaitTransactionSuccessAsync(
- await assetProxyDispatcher.registerAssetProxy.sendTransactionAsync(erc721Proxy.address, {
- from: owner,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- proxyAddress = await assetProxyDispatcher.getAssetProxy.callAsync(AssetProxyId.ERC721);
- expect(proxyAddress).to.be.equal(erc721Proxy.address);
- });
-
- it('should throw if a proxy with the same id is already registered', async () => {
- // Initial registration
- await web3Wrapper.awaitTransactionSuccessAsync(
- await assetProxyDispatcher.registerAssetProxy.sendTransactionAsync(erc20Proxy.address, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const proxyAddress = await assetProxyDispatcher.getAssetProxy.callAsync(AssetProxyId.ERC20);
- expect(proxyAddress).to.be.equal(erc20Proxy.address);
- // Deploy a new version of the ERC20 Transfer Proxy contract
- const newErc20TransferProxy = await ERC20ProxyContract.deployFrom0xArtifactAsync(
- artifacts.ERC20Proxy,
- provider,
- txDefaults,
- );
- // Register new ERC20 Transfer Proxy contract
- return expectTransactionFailedAsync(
- assetProxyDispatcher.registerAssetProxy.sendTransactionAsync(newErc20TransferProxy.address, {
- from: owner,
- }),
- RevertReason.AssetProxyAlreadyExists,
- );
- });
-
- it('should throw if requesting address is not owner', async () => {
- return expectTransactionFailedAsync(
- assetProxyDispatcher.registerAssetProxy.sendTransactionAsync(erc20Proxy.address, { from: notOwner }),
- RevertReason.OnlyContractOwner,
- );
- });
-
- it('should log an event with correct arguments when an asset proxy is registered', async () => {
- const logDecoder = new LogDecoder(web3Wrapper);
- const txReceipt = await logDecoder.getTxWithDecodedLogsAsync(
- await assetProxyDispatcher.registerAssetProxy.sendTransactionAsync(erc20Proxy.address, { from: owner }),
- );
- const logs = txReceipt.logs;
- const log = logs[0] as LogWithDecodedArgs<TestAssetProxyDispatcherAssetProxyRegisteredEventArgs>;
- expect(log.args.id).to.equal(AssetProxyId.ERC20);
- expect(log.args.assetProxy).to.equal(erc20Proxy.address);
- });
- });
-
- describe('getAssetProxy', () => {
- it('should return correct address of registered proxy', async () => {
- await web3Wrapper.awaitTransactionSuccessAsync(
- await assetProxyDispatcher.registerAssetProxy.sendTransactionAsync(erc20Proxy.address, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const proxyAddress = await assetProxyDispatcher.getAssetProxy.callAsync(AssetProxyId.ERC20);
- expect(proxyAddress).to.be.equal(erc20Proxy.address);
- });
-
- it('should return NULL address if requesting non-existent proxy', async () => {
- const proxyAddress = await assetProxyDispatcher.getAssetProxy.callAsync(AssetProxyId.ERC20);
- expect(proxyAddress).to.be.equal(constants.NULL_ADDRESS);
- });
- });
-
- describe('dispatchTransferFrom', () => {
- it('should dispatch transfer to registered proxy', async () => {
- // Register ERC20 proxy
- await web3Wrapper.awaitTransactionSuccessAsync(
- await assetProxyDispatcher.registerAssetProxy.sendTransactionAsync(erc20Proxy.address, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- // Construct metadata for ERC20 proxy
- const encodedAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address);
-
- // Perform a transfer from makerAddress to takerAddress
- const erc20Balances = await erc20Wrapper.getBalancesAsync();
- const amount = new BigNumber(10);
- await web3Wrapper.awaitTransactionSuccessAsync(
- await assetProxyDispatcher.publicDispatchTransferFrom.sendTransactionAsync(
- encodedAssetData,
- makerAddress,
- takerAddress,
- amount,
- { from: owner },
- ),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- // Verify transfer was successful
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(newBalances[makerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][zrxToken.address].minus(amount),
- );
- expect(newBalances[takerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[takerAddress][zrxToken.address].add(amount),
- );
- });
-
- it('should not dispatch a transfer if amount == 0', async () => {
- // Register ERC20 proxy
- await web3Wrapper.awaitTransactionSuccessAsync(
- await assetProxyDispatcher.registerAssetProxy.sendTransactionAsync(erc20Proxy.address, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- // Construct metadata for ERC20 proxy
- const encodedAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address);
-
- // Perform a transfer from makerAddress to takerAddress
- const erc20Balances = await erc20Wrapper.getBalancesAsync();
- const amount = constants.ZERO_AMOUNT;
- const txReceipt = await web3Wrapper.awaitTransactionSuccessAsync(
- await assetProxyDispatcher.publicDispatchTransferFrom.sendTransactionAsync(
- encodedAssetData,
- makerAddress,
- takerAddress,
- amount,
- { from: owner },
- ),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- expect(txReceipt.logs.length).to.be.equal(0);
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(newBalances).to.deep.equal(erc20Balances);
- });
-
- it('should not dispatch a transfer if from == to', async () => {
- // Register ERC20 proxy
- await web3Wrapper.awaitTransactionSuccessAsync(
- await assetProxyDispatcher.registerAssetProxy.sendTransactionAsync(erc20Proxy.address, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- // Construct metadata for ERC20 proxy
- const encodedAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address);
-
- // Perform a transfer from makerAddress to takerAddress
- const erc20Balances = await erc20Wrapper.getBalancesAsync();
- const amount = new BigNumber(10);
- const txReceipt = await web3Wrapper.awaitTransactionSuccessAsync(
- await assetProxyDispatcher.publicDispatchTransferFrom.sendTransactionAsync(
- encodedAssetData,
- makerAddress,
- makerAddress,
- amount,
- { from: owner },
- ),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- expect(txReceipt.logs.length).to.be.equal(0);
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(newBalances).to.deep.equal(erc20Balances);
- });
-
- it('should throw if dispatching to unregistered proxy', async () => {
- // Construct metadata for ERC20 proxy
- const encodedAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address);
- // Perform a transfer from makerAddress to takerAddress
- const amount = new BigNumber(10);
- return expectTransactionFailedAsync(
- assetProxyDispatcher.publicDispatchTransferFrom.sendTransactionAsync(
- encodedAssetData,
- makerAddress,
- takerAddress,
- amount,
- { from: owner },
- ),
- RevertReason.AssetProxyDoesNotExist,
- );
- });
- });
-});
-// tslint:enable:no-unnecessary-type-assertion
diff --git a/packages/contracts/test/exchange/fill_order.ts b/packages/contracts/test/exchange/fill_order.ts
deleted file mode 100644
index 37efaad2b..000000000
--- a/packages/contracts/test/exchange/fill_order.ts
+++ /dev/null
@@ -1,312 +0,0 @@
-import { BlockchainLifecycle } from '@0x/dev-utils';
-import * as _ from 'lodash';
-
-import { chaiSetup } from '../utils/chai_setup';
-import {
- FillOrderCombinatorialUtils,
- fillOrderCombinatorialUtilsFactoryAsync,
-} from '../utils/fill_order_combinatorial_utils';
-import {
- AllowanceAmountScenario,
- AssetDataScenario,
- BalanceAmountScenario,
- ExpirationTimeSecondsScenario,
- FeeRecipientAddressScenario,
- FillScenario,
- OrderAssetAmountScenario,
- TakerAssetFillAmountScenario,
- TakerScenario,
-} from '../utils/types';
-import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper';
-
-chaiSetup.configure();
-const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
-
-const defaultFillScenario = {
- orderScenario: {
- takerScenario: TakerScenario.Unspecified,
- feeRecipientScenario: FeeRecipientAddressScenario.EthUserAddress,
- makerAssetAmountScenario: OrderAssetAmountScenario.Large,
- takerAssetAmountScenario: OrderAssetAmountScenario.Large,
- makerFeeScenario: OrderAssetAmountScenario.Large,
- takerFeeScenario: OrderAssetAmountScenario.Large,
- expirationTimeSecondsScenario: ExpirationTimeSecondsScenario.InFuture,
- makerAssetDataScenario: AssetDataScenario.ERC20NonZRXEighteenDecimals,
- takerAssetDataScenario: AssetDataScenario.ERC20NonZRXEighteenDecimals,
- },
- takerAssetFillAmountScenario: TakerAssetFillAmountScenario.LessThanRemainingFillableTakerAssetAmount,
- makerStateScenario: {
- traderAssetBalance: BalanceAmountScenario.Higher,
- traderAssetAllowance: AllowanceAmountScenario.Higher,
- zrxFeeBalance: BalanceAmountScenario.Higher,
- zrxFeeAllowance: AllowanceAmountScenario.Higher,
- },
- takerStateScenario: {
- traderAssetBalance: BalanceAmountScenario.Higher,
- traderAssetAllowance: AllowanceAmountScenario.Higher,
- zrxFeeBalance: BalanceAmountScenario.Higher,
- zrxFeeAllowance: AllowanceAmountScenario.Higher,
- },
-};
-
-describe('FillOrder Tests', () => {
- let fillOrderCombinatorialUtils: FillOrderCombinatorialUtils;
-
- before(async () => {
- await blockchainLifecycle.startAsync();
- fillOrderCombinatorialUtils = await fillOrderCombinatorialUtilsFactoryAsync(web3Wrapper, txDefaults);
- });
- after(async () => {
- await blockchainLifecycle.revertAsync();
- });
- beforeEach(async () => {
- await blockchainLifecycle.startAsync();
- });
- afterEach(async () => {
- await blockchainLifecycle.revertAsync();
- });
- describe('fillOrder', () => {
- const test = (fillScenarios: FillScenario[]) => {
- _.forEach(fillScenarios, fillScenario => {
- const description = `Combinatorial OrderFill: ${JSON.stringify(fillScenario)}`;
- it(description, async () => {
- await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
- });
- });
- };
-
- const allFillScenarios = FillOrderCombinatorialUtils.generateFillOrderCombinations();
- describe('Combinatorially generated fills orders', () => test(allFillScenarios));
-
- it('should transfer the correct amounts when makerAssetAmount === takerAssetAmount', async () => {
- const fillScenario = {
- ...defaultFillScenario,
- };
- await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
- });
- it('should transfer the correct amounts when makerAssetAmount > takerAssetAmount', async () => {
- const fillScenario = {
- ...defaultFillScenario,
- orderScenario: {
- ...defaultFillScenario.orderScenario,
- takerAssetAmountScenario: OrderAssetAmountScenario.Small,
- },
- };
- await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
- });
- it('should transfer the correct amounts when makerAssetAmount < takerAssetAmount', async () => {
- const fillScenario = {
- ...defaultFillScenario,
- orderScenario: {
- ...defaultFillScenario.orderScenario,
- makerAssetAmountScenario: OrderAssetAmountScenario.Small,
- },
- };
- await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
- });
- it('should transfer the correct amounts when makerAssetAmount < takerAssetAmount with zero decimals', async () => {
- const fillScenario = {
- ...defaultFillScenario,
- orderScenario: {
- ...defaultFillScenario.orderScenario,
- makerAssetAmountScenario: OrderAssetAmountScenario.Small,
- makerAssetDataScenario: AssetDataScenario.ERC20ZeroDecimals,
- },
- };
- await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
- });
- it('should transfer the correct amounts when taker is specified and order is claimed by taker', async () => {
- const fillScenario = {
- ...defaultFillScenario,
- orderScenario: {
- ...defaultFillScenario.orderScenario,
- takerScenario: TakerScenario.CorrectlySpecified,
- },
- };
- await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
- });
- it('should fill remaining value if takerAssetFillAmount > remaining takerAssetAmount', async () => {
- const fillScenario = {
- ...defaultFillScenario,
- takerAssetFillAmountScenario: TakerAssetFillAmountScenario.GreaterThanRemainingFillableTakerAssetAmount,
- };
- await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
- });
- it('should throw when taker is specified and order is claimed by other', async () => {
- const fillScenario = {
- ...defaultFillScenario,
- orderScenario: {
- ...defaultFillScenario.orderScenario,
- takerScenario: TakerScenario.IncorrectlySpecified,
- },
- };
- await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
- });
-
- it('should throw if makerAssetAmount is 0', async () => {
- const fillScenario = {
- ...defaultFillScenario,
- orderScenario: {
- ...defaultFillScenario.orderScenario,
- makerAssetAmountScenario: OrderAssetAmountScenario.Zero,
- },
- takerAssetFillAmountScenario: TakerAssetFillAmountScenario.GreaterThanRemainingFillableTakerAssetAmount,
- };
- await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
- });
-
- it('should throw if takerAssetAmount is 0', async () => {
- const fillScenario = {
- ...defaultFillScenario,
- orderScenario: {
- ...defaultFillScenario.orderScenario,
- takerAssetAmountScenario: OrderAssetAmountScenario.Zero,
- },
- takerAssetFillAmountScenario: TakerAssetFillAmountScenario.GreaterThanRemainingFillableTakerAssetAmount,
- };
- await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
- });
-
- it('should throw if takerAssetFillAmount is 0', async () => {
- const fillScenario = {
- ...defaultFillScenario,
- takerAssetFillAmountScenario: TakerAssetFillAmountScenario.Zero,
- };
- await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
- });
-
- it('should throw if an order is expired', async () => {
- const fillScenario = {
- ...defaultFillScenario,
- orderScenario: {
- ...defaultFillScenario.orderScenario,
- expirationTimeSecondsScenario: ExpirationTimeSecondsScenario.InPast,
- },
- };
- await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
- });
-
- it('should throw if maker erc20Balances are too low to fill order', async () => {
- const fillScenario = {
- ...defaultFillScenario,
- makerStateScenario: {
- ...defaultFillScenario.makerStateScenario,
- traderAssetBalance: BalanceAmountScenario.TooLow,
- },
- };
- await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
- });
-
- it('should throw if taker erc20Balances are too low to fill order', async () => {
- const fillScenario = {
- ...defaultFillScenario,
- takerStateScenario: {
- ...defaultFillScenario.makerStateScenario,
- traderAssetBalance: BalanceAmountScenario.TooLow,
- },
- };
- await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
- });
-
- it('should throw if maker allowances are too low to fill order', async () => {
- const fillScenario = {
- ...defaultFillScenario,
- makerStateScenario: {
- ...defaultFillScenario.makerStateScenario,
- traderAssetAllowance: AllowanceAmountScenario.TooLow,
- },
- };
- await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
- });
-
- it('should throw if taker allowances are too low to fill order', async () => {
- const fillScenario = {
- ...defaultFillScenario,
- takerStateScenario: {
- ...defaultFillScenario.makerStateScenario,
- traderAssetAllowance: AllowanceAmountScenario.TooLow,
- },
- };
- await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
- });
- });
-
- describe('Testing exchange of ERC721 Tokens', () => {
- it('should successfully exchange a single token between the maker and taker (via fillOrder)', async () => {
- const fillScenario = {
- ...defaultFillScenario,
- orderScenario: {
- ...defaultFillScenario.orderScenario,
- makerAssetDataScenario: AssetDataScenario.ERC721,
- takerAssetDataScenario: AssetDataScenario.ERC721,
- },
- takerAssetFillAmountScenario: TakerAssetFillAmountScenario.ExactlyRemainingFillableTakerAssetAmount,
- };
- await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
- });
-
- it('should successfully fill order when makerAsset is ERC721 and takerAsset is ERC20', async () => {
- const fillScenario = {
- ...defaultFillScenario,
- orderScenario: {
- ...defaultFillScenario.orderScenario,
- makerAssetDataScenario: AssetDataScenario.ERC721,
- takerAssetDataScenario: AssetDataScenario.ERC20NonZRXEighteenDecimals,
- },
- takerAssetFillAmountScenario: TakerAssetFillAmountScenario.ExactlyRemainingFillableTakerAssetAmount,
- };
- await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario, true);
- });
-
- it('should successfully fill order when makerAsset is ERC20 and takerAsset is ERC721', async () => {
- const fillScenario = {
- ...defaultFillScenario,
- orderScenario: {
- ...defaultFillScenario.orderScenario,
- makerAssetDataScenario: AssetDataScenario.ERC20NonZRXEighteenDecimals,
- takerAssetDataScenario: AssetDataScenario.ERC721,
- },
- takerAssetFillAmountScenario: TakerAssetFillAmountScenario.ExactlyRemainingFillableTakerAssetAmount,
- };
- await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
- });
-
- it('should successfully fill order when makerAsset is ERC721 and approveAll is set for it', async () => {
- const fillScenario = {
- ...defaultFillScenario,
- orderScenario: {
- ...defaultFillScenario.orderScenario,
- makerAssetDataScenario: AssetDataScenario.ERC721,
- takerAssetDataScenario: AssetDataScenario.ERC20NonZRXEighteenDecimals,
- },
- takerAssetFillAmountScenario: TakerAssetFillAmountScenario.ExactlyRemainingFillableTakerAssetAmount,
- makerStateScenario: {
- ...defaultFillScenario.makerStateScenario,
- traderAssetAllowance: AllowanceAmountScenario.Unlimited,
- },
- };
- await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
- });
-
- it('should successfully fill order when makerAsset and takerAsset are ERC721 and approveAll is set for them', async () => {
- const fillScenario = {
- ...defaultFillScenario,
- orderScenario: {
- ...defaultFillScenario.orderScenario,
- makerAssetDataScenario: AssetDataScenario.ERC721,
- takerAssetDataScenario: AssetDataScenario.ERC721,
- },
- takerAssetFillAmountScenario: TakerAssetFillAmountScenario.ExactlyRemainingFillableTakerAssetAmount,
- makerStateScenario: {
- ...defaultFillScenario.makerStateScenario,
- traderAssetAllowance: AllowanceAmountScenario.Unlimited,
- },
- takerStateScenario: {
- ...defaultFillScenario.takerStateScenario,
- traderAssetAllowance: AllowanceAmountScenario.Unlimited,
- },
- };
- await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
- });
- });
-});
diff --git a/packages/contracts/test/exchange/internal.ts b/packages/contracts/test/exchange/internal.ts
deleted file mode 100644
index 109be29c6..000000000
--- a/packages/contracts/test/exchange/internal.ts
+++ /dev/null
@@ -1,466 +0,0 @@
-import { BlockchainLifecycle } from '@0x/dev-utils';
-import { Order, RevertReason, SignedOrder } from '@0x/types';
-import { BigNumber } from '@0x/utils';
-import * as chai from 'chai';
-import * as _ from 'lodash';
-
-import { TestExchangeInternalsContract } from '../../generated-wrappers/test_exchange_internals';
-import { artifacts } from '../../src/artifacts';
-import { getRevertReasonOrErrorMessageForSendTransactionAsync } from '../utils/assertions';
-import { chaiSetup } from '../utils/chai_setup';
-import { bytes32Values, testCombinatoriallyWithReferenceFuncAsync, uint256Values } from '../utils/combinatorial_utils';
-import { constants } from '../utils/constants';
-import { FillResults } from '../utils/types';
-import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper';
-
-chaiSetup.configure();
-const expect = chai.expect;
-
-const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
-
-const MAX_UINT256 = new BigNumber(2).pow(256).minus(1);
-
-const emptyOrder: Order = {
- senderAddress: constants.NULL_ADDRESS,
- makerAddress: constants.NULL_ADDRESS,
- takerAddress: constants.NULL_ADDRESS,
- makerFee: new BigNumber(0),
- takerFee: new BigNumber(0),
- makerAssetAmount: new BigNumber(0),
- takerAssetAmount: new BigNumber(0),
- makerAssetData: '0x',
- takerAssetData: '0x',
- salt: new BigNumber(0),
- exchangeAddress: constants.NULL_ADDRESS,
- feeRecipientAddress: constants.NULL_ADDRESS,
- expirationTimeSeconds: new BigNumber(0),
-};
-
-const emptySignedOrder: SignedOrder = {
- ...emptyOrder,
- signature: '',
-};
-
-const overflowErrorForCall = new Error(RevertReason.Uint256Overflow);
-
-describe('Exchange core internal functions', () => {
- let testExchange: TestExchangeInternalsContract;
- let overflowErrorForSendTransaction: Error | undefined;
- let divisionByZeroErrorForCall: Error | undefined;
- let roundingErrorForCall: Error | undefined;
-
- before(async () => {
- await blockchainLifecycle.startAsync();
- });
- after(async () => {
- await blockchainLifecycle.revertAsync();
- });
- before(async () => {
- testExchange = await TestExchangeInternalsContract.deployFrom0xArtifactAsync(
- artifacts.TestExchangeInternals,
- provider,
- txDefaults,
- );
- overflowErrorForSendTransaction = new Error(
- await getRevertReasonOrErrorMessageForSendTransactionAsync(RevertReason.Uint256Overflow),
- );
- divisionByZeroErrorForCall = new Error(RevertReason.DivisionByZero);
- roundingErrorForCall = new Error(RevertReason.RoundingError);
- });
- // Note(albrow): Don't forget to add beforeEach and afterEach calls to reset
- // the blockchain state for any tests which modify it!
-
- async function referenceIsRoundingErrorFloorAsync(
- numerator: BigNumber,
- denominator: BigNumber,
- target: BigNumber,
- ): Promise<boolean> {
- if (denominator.eq(0)) {
- throw divisionByZeroErrorForCall;
- }
- if (numerator.eq(0)) {
- return false;
- }
- if (target.eq(0)) {
- return false;
- }
- const product = numerator.mul(target);
- const remainder = product.mod(denominator);
- const remainderTimes1000 = remainder.mul('1000');
- const isError = remainderTimes1000.gte(product);
- if (product.greaterThan(MAX_UINT256)) {
- throw overflowErrorForCall;
- }
- if (remainderTimes1000.greaterThan(MAX_UINT256)) {
- throw overflowErrorForCall;
- }
- return isError;
- }
-
- async function referenceIsRoundingErrorCeilAsync(
- numerator: BigNumber,
- denominator: BigNumber,
- target: BigNumber,
- ): Promise<boolean> {
- if (denominator.eq(0)) {
- throw divisionByZeroErrorForCall;
- }
- if (numerator.eq(0)) {
- return false;
- }
- if (target.eq(0)) {
- return false;
- }
- const product = numerator.mul(target);
- const remainder = product.mod(denominator);
- const error = denominator.sub(remainder).mod(denominator);
- const errorTimes1000 = error.mul('1000');
- const isError = errorTimes1000.gte(product);
- if (product.greaterThan(MAX_UINT256)) {
- throw overflowErrorForCall;
- }
- if (errorTimes1000.greaterThan(MAX_UINT256)) {
- throw overflowErrorForCall;
- }
- return isError;
- }
-
- async function referenceSafeGetPartialAmountFloorAsync(
- numerator: BigNumber,
- denominator: BigNumber,
- target: BigNumber,
- ): Promise<BigNumber> {
- if (denominator.eq(0)) {
- throw divisionByZeroErrorForCall;
- }
- const isRoundingError = await referenceIsRoundingErrorFloorAsync(numerator, denominator, target);
- if (isRoundingError) {
- throw roundingErrorForCall;
- }
- const product = numerator.mul(target);
- if (product.greaterThan(MAX_UINT256)) {
- throw overflowErrorForCall;
- }
- return product.dividedToIntegerBy(denominator);
- }
-
- describe('addFillResults', async () => {
- function makeFillResults(value: BigNumber): FillResults {
- return {
- makerAssetFilledAmount: value,
- takerAssetFilledAmount: value,
- makerFeePaid: value,
- takerFeePaid: value,
- };
- }
- async function referenceAddFillResultsAsync(
- totalValue: BigNumber,
- singleValue: BigNumber,
- ): Promise<FillResults> {
- // Note(albrow): Here, each of totalFillResults and
- // singleFillResults will consist of fields with the same values.
- // This should be safe because none of the fields in a given
- // FillResults are ever used together in a mathemetical operation.
- // They are only used with the corresponding field from *the other*
- // FillResults, which are different.
- const totalFillResults = makeFillResults(totalValue);
- const singleFillResults = makeFillResults(singleValue);
- // HACK(albrow): _.mergeWith mutates the first argument! To
- // workaround this we use _.cloneDeep.
- return _.mergeWith(
- _.cloneDeep(totalFillResults),
- singleFillResults,
- (totalVal: BigNumber, singleVal: BigNumber) => {
- const newTotal = totalVal.add(singleVal);
- if (newTotal.greaterThan(MAX_UINT256)) {
- throw overflowErrorForCall;
- }
- return newTotal;
- },
- );
- }
- async function testAddFillResultsAsync(totalValue: BigNumber, singleValue: BigNumber): Promise<FillResults> {
- const totalFillResults = makeFillResults(totalValue);
- const singleFillResults = makeFillResults(singleValue);
- return testExchange.publicAddFillResults.callAsync(totalFillResults, singleFillResults);
- }
- await testCombinatoriallyWithReferenceFuncAsync(
- 'addFillResults',
- referenceAddFillResultsAsync,
- testAddFillResultsAsync,
- [uint256Values, uint256Values],
- );
- });
-
- describe('calculateFillResults', async () => {
- function makeOrder(
- makerAssetAmount: BigNumber,
- takerAssetAmount: BigNumber,
- makerFee: BigNumber,
- takerFee: BigNumber,
- ): Order {
- return {
- ...emptyOrder,
- makerAssetAmount,
- takerAssetAmount,
- makerFee,
- takerFee,
- };
- }
- async function referenceCalculateFillResultsAsync(
- orderTakerAssetAmount: BigNumber,
- takerAssetFilledAmount: BigNumber,
- otherAmount: BigNumber,
- ): Promise<FillResults> {
- // Note(albrow): Here we are re-using the same value (otherAmount)
- // for order.makerAssetAmount, order.makerFee, and order.takerFee.
- // This should be safe because they are never used with each other
- // in any mathematical operation in either the reference TypeScript
- // implementation or the Solidity implementation of
- // calculateFillResults.
- const makerAssetFilledAmount = await referenceSafeGetPartialAmountFloorAsync(
- takerAssetFilledAmount,
- orderTakerAssetAmount,
- otherAmount,
- );
- const order = makeOrder(otherAmount, orderTakerAssetAmount, otherAmount, otherAmount);
- const orderMakerAssetAmount = order.makerAssetAmount;
- return {
- makerAssetFilledAmount,
- takerAssetFilledAmount,
- makerFeePaid: await referenceSafeGetPartialAmountFloorAsync(
- makerAssetFilledAmount,
- orderMakerAssetAmount,
- otherAmount,
- ),
- takerFeePaid: await referenceSafeGetPartialAmountFloorAsync(
- takerAssetFilledAmount,
- orderTakerAssetAmount,
- otherAmount,
- ),
- };
- }
- async function testCalculateFillResultsAsync(
- orderTakerAssetAmount: BigNumber,
- takerAssetFilledAmount: BigNumber,
- otherAmount: BigNumber,
- ): Promise<FillResults> {
- const order = makeOrder(otherAmount, orderTakerAssetAmount, otherAmount, otherAmount);
- return testExchange.publicCalculateFillResults.callAsync(order, takerAssetFilledAmount);
- }
- await testCombinatoriallyWithReferenceFuncAsync(
- 'calculateFillResults',
- referenceCalculateFillResultsAsync,
- testCalculateFillResultsAsync,
- [uint256Values, uint256Values, uint256Values],
- );
- });
-
- describe('getPartialAmountFloor', async () => {
- async function referenceGetPartialAmountFloorAsync(
- numerator: BigNumber,
- denominator: BigNumber,
- target: BigNumber,
- ): Promise<BigNumber> {
- if (denominator.eq(0)) {
- throw divisionByZeroErrorForCall;
- }
- const product = numerator.mul(target);
- if (product.greaterThan(MAX_UINT256)) {
- throw overflowErrorForCall;
- }
- return product.dividedToIntegerBy(denominator);
- }
- async function testGetPartialAmountFloorAsync(
- numerator: BigNumber,
- denominator: BigNumber,
- target: BigNumber,
- ): Promise<BigNumber> {
- return testExchange.publicGetPartialAmountFloor.callAsync(numerator, denominator, target);
- }
- await testCombinatoriallyWithReferenceFuncAsync(
- 'getPartialAmountFloor',
- referenceGetPartialAmountFloorAsync,
- testGetPartialAmountFloorAsync,
- [uint256Values, uint256Values, uint256Values],
- );
- });
-
- describe('getPartialAmountCeil', async () => {
- async function referenceGetPartialAmountCeilAsync(
- numerator: BigNumber,
- denominator: BigNumber,
- target: BigNumber,
- ): Promise<BigNumber> {
- if (denominator.eq(0)) {
- throw divisionByZeroErrorForCall;
- }
- const product = numerator.mul(target);
- const offset = product.add(denominator.sub(1));
- if (offset.greaterThan(MAX_UINT256)) {
- throw overflowErrorForCall;
- }
- const result = offset.dividedToIntegerBy(denominator);
- if (product.mod(denominator).eq(0)) {
- expect(result.mul(denominator)).to.be.bignumber.eq(product);
- } else {
- expect(result.mul(denominator)).to.be.bignumber.gt(product);
- }
- return result;
- }
- async function testGetPartialAmountCeilAsync(
- numerator: BigNumber,
- denominator: BigNumber,
- target: BigNumber,
- ): Promise<BigNumber> {
- return testExchange.publicGetPartialAmountCeil.callAsync(numerator, denominator, target);
- }
- await testCombinatoriallyWithReferenceFuncAsync(
- 'getPartialAmountCeil',
- referenceGetPartialAmountCeilAsync,
- testGetPartialAmountCeilAsync,
- [uint256Values, uint256Values, uint256Values],
- );
- });
-
- describe('safeGetPartialAmountFloor', async () => {
- async function testSafeGetPartialAmountFloorAsync(
- numerator: BigNumber,
- denominator: BigNumber,
- target: BigNumber,
- ): Promise<BigNumber> {
- return testExchange.publicSafeGetPartialAmountFloor.callAsync(numerator, denominator, target);
- }
- await testCombinatoriallyWithReferenceFuncAsync(
- 'safeGetPartialAmountFloor',
- referenceSafeGetPartialAmountFloorAsync,
- testSafeGetPartialAmountFloorAsync,
- [uint256Values, uint256Values, uint256Values],
- );
- });
-
- describe('safeGetPartialAmountCeil', async () => {
- async function referenceSafeGetPartialAmountCeilAsync(
- numerator: BigNumber,
- denominator: BigNumber,
- target: BigNumber,
- ): Promise<BigNumber> {
- if (denominator.eq(0)) {
- throw divisionByZeroErrorForCall;
- }
- const isRoundingError = await referenceIsRoundingErrorCeilAsync(numerator, denominator, target);
- if (isRoundingError) {
- throw roundingErrorForCall;
- }
- const product = numerator.mul(target);
- const offset = product.add(denominator.sub(1));
- if (offset.greaterThan(MAX_UINT256)) {
- throw overflowErrorForCall;
- }
- const result = offset.dividedToIntegerBy(denominator);
- if (product.mod(denominator).eq(0)) {
- expect(result.mul(denominator)).to.be.bignumber.eq(product);
- } else {
- expect(result.mul(denominator)).to.be.bignumber.gt(product);
- }
- return result;
- }
- async function testSafeGetPartialAmountCeilAsync(
- numerator: BigNumber,
- denominator: BigNumber,
- target: BigNumber,
- ): Promise<BigNumber> {
- return testExchange.publicSafeGetPartialAmountCeil.callAsync(numerator, denominator, target);
- }
- await testCombinatoriallyWithReferenceFuncAsync(
- 'safeGetPartialAmountCeil',
- referenceSafeGetPartialAmountCeilAsync,
- testSafeGetPartialAmountCeilAsync,
- [uint256Values, uint256Values, uint256Values],
- );
- });
-
- describe('isRoundingErrorFloor', async () => {
- async function testIsRoundingErrorFloorAsync(
- numerator: BigNumber,
- denominator: BigNumber,
- target: BigNumber,
- ): Promise<boolean> {
- return testExchange.publicIsRoundingErrorFloor.callAsync(numerator, denominator, target);
- }
- await testCombinatoriallyWithReferenceFuncAsync(
- 'isRoundingErrorFloor',
- referenceIsRoundingErrorFloorAsync,
- testIsRoundingErrorFloorAsync,
- [uint256Values, uint256Values, uint256Values],
- );
- });
-
- describe('isRoundingErrorCeil', async () => {
- async function testIsRoundingErrorCeilAsync(
- numerator: BigNumber,
- denominator: BigNumber,
- target: BigNumber,
- ): Promise<boolean> {
- return testExchange.publicIsRoundingErrorCeil.callAsync(numerator, denominator, target);
- }
- await testCombinatoriallyWithReferenceFuncAsync(
- 'isRoundingErrorCeil',
- referenceIsRoundingErrorCeilAsync,
- testIsRoundingErrorCeilAsync,
- [uint256Values, uint256Values, uint256Values],
- );
- });
-
- describe('updateFilledState', async () => {
- // Note(albrow): Since updateFilledState modifies the state by calling
- // sendTransaction, we must reset the state after each test.
- beforeEach(async () => {
- await blockchainLifecycle.startAsync();
- });
- afterEach(async () => {
- await blockchainLifecycle.revertAsync();
- });
- async function referenceUpdateFilledStateAsync(
- takerAssetFilledAmount: BigNumber,
- orderTakerAssetFilledAmount: BigNumber,
- // tslint:disable-next-line:no-unused-variable
- orderHash: string,
- ): Promise<BigNumber> {
- const totalFilledAmount = takerAssetFilledAmount.add(orderTakerAssetFilledAmount);
- if (totalFilledAmount.greaterThan(MAX_UINT256)) {
- throw overflowErrorForSendTransaction;
- }
- return totalFilledAmount;
- }
- async function testUpdateFilledStateAsync(
- takerAssetFilledAmount: BigNumber,
- orderTakerAssetFilledAmount: BigNumber,
- orderHash: string,
- ): Promise<BigNumber> {
- const fillResults = {
- makerAssetFilledAmount: new BigNumber(0),
- takerAssetFilledAmount,
- makerFeePaid: new BigNumber(0),
- takerFeePaid: new BigNumber(0),
- };
- await web3Wrapper.awaitTransactionSuccessAsync(
- await testExchange.publicUpdateFilledState.sendTransactionAsync(
- emptySignedOrder,
- constants.NULL_ADDRESS,
- orderHash,
- orderTakerAssetFilledAmount,
- fillResults,
- ),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- return testExchange.filled.callAsync(orderHash);
- }
- await testCombinatoriallyWithReferenceFuncAsync(
- 'updateFilledState',
- referenceUpdateFilledStateAsync,
- testUpdateFilledStateAsync,
- [uint256Values, uint256Values, bytes32Values],
- );
- });
-});
diff --git a/packages/contracts/test/exchange/libs.ts b/packages/contracts/test/exchange/libs.ts
deleted file mode 100644
index 503ef0e0f..000000000
--- a/packages/contracts/test/exchange/libs.ts
+++ /dev/null
@@ -1,137 +0,0 @@
-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 { TestConstantsContract } from '../../generated-wrappers/test_constants';
-import { TestLibsContract } from '../../generated-wrappers/test_libs';
-import { artifacts } from '../../src/artifacts';
-import { addressUtils } from '../utils/address_utils';
-import { chaiSetup } from '../utils/chai_setup';
-import { constants } from '../utils/constants';
-import { OrderFactory } from '../utils/order_factory';
-import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper';
-
-chaiSetup.configure();
-const expect = chai.expect;
-
-const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
-
-describe('Exchange libs', () => {
- let signedOrder: SignedOrder;
- let orderFactory: OrderFactory;
- let libs: TestLibsContract;
- let testConstants: TestConstantsContract;
-
- before(async () => {
- await blockchainLifecycle.startAsync();
- });
- after(async () => {
- await blockchainLifecycle.revertAsync();
- });
- before(async () => {
- const accounts = await web3Wrapper.getAvailableAddressesAsync();
- const makerAddress = accounts[0];
- libs = await TestLibsContract.deployFrom0xArtifactAsync(artifacts.TestLibs, provider, txDefaults);
- testConstants = await TestConstantsContract.deployFrom0xArtifactAsync(
- artifacts.TestConstants,
- provider,
- txDefaults,
- );
-
- const defaultOrderParams = {
- ...constants.STATIC_ORDER_PARAMS,
- exchangeAddress: libs.address,
- makerAddress,
- feeRecipientAddress: addressUtils.generatePseudoRandomAddress(),
- makerAssetData: assetDataUtils.encodeERC20AssetData(addressUtils.generatePseudoRandomAddress()),
- takerAssetData: assetDataUtils.encodeERC20AssetData(addressUtils.generatePseudoRandomAddress()),
- };
- 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('LibConstants', () => {
- describe('ZRX_ASSET_DATA', () => {
- it('should have the correct ZRX_ASSET_DATA', async () => {
- const isValid = await testConstants.assertValidZrxAssetData.callAsync();
- expect(isValid).to.be.equal(true);
- });
- });
- });
- // Note(albrow): These tests are designed to be supplemental to the
- // combinatorial tests in test/exchange/internal. They test specific edge
- // cases that are not covered by the combinatorial tests.
- describe('LibMath', () => {
- describe('isRoundingError', () => {
- it('should return true if there is a rounding error of 0.1%', async () => {
- const numerator = new BigNumber(20);
- const denominator = new BigNumber(999);
- const target = new BigNumber(50);
- // rounding error = ((20*50/999) - floor(20*50/999)) / (20*50/999) = 0.1%
- const isRoundingError = await libs.publicIsRoundingErrorFloor.callAsync(numerator, denominator, target);
- expect(isRoundingError).to.be.true();
- });
- it('should return false if there is a rounding of 0.09%', async () => {
- const numerator = new BigNumber(20);
- const denominator = new BigNumber(9991);
- const target = new BigNumber(500);
- // rounding error = ((20*500/9991) - floor(20*500/9991)) / (20*500/9991) = 0.09%
- const isRoundingError = await libs.publicIsRoundingErrorFloor.callAsync(numerator, denominator, target);
- expect(isRoundingError).to.be.false();
- });
- it('should return true if there is a rounding error of 0.11%', async () => {
- const numerator = new BigNumber(20);
- const denominator = new BigNumber(9989);
- const target = new BigNumber(500);
- // rounding error = ((20*500/9989) - floor(20*500/9989)) / (20*500/9989) = 0.011%
- const isRoundingError = await libs.publicIsRoundingErrorFloor.callAsync(numerator, denominator, target);
- expect(isRoundingError).to.be.true();
- });
- });
- describe('isRoundingErrorCeil', () => {
- it('should return true if there is a rounding error of 0.1%', async () => {
- const numerator = new BigNumber(20);
- const denominator = new BigNumber(1001);
- const target = new BigNumber(50);
- // rounding error = (ceil(20*50/1001) - (20*50/1001)) / (20*50/1001) = 0.1%
- const isRoundingError = await libs.publicIsRoundingErrorCeil.callAsync(numerator, denominator, target);
- expect(isRoundingError).to.be.true();
- });
- it('should return false if there is a rounding of 0.09%', async () => {
- const numerator = new BigNumber(20);
- const denominator = new BigNumber(10009);
- const target = new BigNumber(500);
- // rounding error = (ceil(20*500/10009) - (20*500/10009)) / (20*500/10009) = 0.09%
- const isRoundingError = await libs.publicIsRoundingErrorCeil.callAsync(numerator, denominator, target);
- expect(isRoundingError).to.be.false();
- });
- it('should return true if there is a rounding error of 0.11%', async () => {
- const numerator = new BigNumber(20);
- const denominator = new BigNumber(10011);
- const target = new BigNumber(500);
- // rounding error = (ceil(20*500/10011) - (20*500/10011)) / (20*500/10011) = 0.11%
- const isRoundingError = await libs.publicIsRoundingErrorCeil.callAsync(numerator, denominator, target);
- expect(isRoundingError).to.be.true();
- });
- });
- });
-
- describe('LibOrder', () => {
- describe('getOrderHash', () => {
- it('should output the correct orderHash', async () => {
- signedOrder = await orderFactory.newSignedOrderAsync();
- const orderHashHex = await libs.publicGetOrderHash.callAsync(signedOrder);
- expect(orderHashUtils.getOrderHashHex(signedOrder)).to.be.equal(orderHashHex);
- });
- });
- });
-});
diff --git a/packages/contracts/test/exchange/match_orders.ts b/packages/contracts/test/exchange/match_orders.ts
deleted file mode 100644
index eea9992d9..000000000
--- a/packages/contracts/test/exchange/match_orders.ts
+++ /dev/null
@@ -1,1276 +0,0 @@
-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 * as _ from 'lodash';
-
-import { DummyERC20TokenContract } from '../../generated-wrappers/dummy_erc20_token';
-import { DummyERC721TokenContract } from '../../generated-wrappers/dummy_erc721_token';
-import { ERC20ProxyContract } from '../../generated-wrappers/erc20_proxy';
-import { ERC721ProxyContract } from '../../generated-wrappers/erc721_proxy';
-import { ExchangeContract } from '../../generated-wrappers/exchange';
-import { ReentrantERC20TokenContract } from '../../generated-wrappers/reentrant_erc20_token';
-import { TestExchangeInternalsContract } from '../../generated-wrappers/test_exchange_internals';
-import { artifacts } from '../../src/artifacts';
-import { expectTransactionFailedAsync } from '../utils/assertions';
-import { chaiSetup } from '../utils/chai_setup';
-import { constants } from '../utils/constants';
-import { ERC20Wrapper } from '../utils/erc20_wrapper';
-import { ERC721Wrapper } from '../utils/erc721_wrapper';
-import { ExchangeWrapper } from '../utils/exchange_wrapper';
-import { MatchOrderTester } from '../utils/match_order_tester';
-import { OrderFactory } from '../utils/order_factory';
-import { ERC20BalancesByOwner, ERC721TokenIdsByOwner } from '../utils/types';
-import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper';
-
-const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
-chaiSetup.configure();
-const expect = chai.expect;
-
-describe('matchOrders', () => {
- 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 erc721Token: DummyERC721TokenContract;
- let reentrantErc20Token: ReentrantERC20TokenContract;
- let exchange: ExchangeContract;
- let erc20Proxy: ERC20ProxyContract;
- let erc721Proxy: ERC721ProxyContract;
-
- let erc20BalancesByOwner: ERC20BalancesByOwner;
- let erc721TokenIdsByOwner: ERC721TokenIdsByOwner;
- let exchangeWrapper: ExchangeWrapper;
- let erc20Wrapper: ERC20Wrapper;
- let erc721Wrapper: ERC721Wrapper;
- let orderFactoryLeft: OrderFactory;
- let orderFactoryRight: OrderFactory;
-
- let erc721LeftMakerAssetIds: BigNumber[];
- let erc721RightMakerAssetIds: BigNumber[];
-
- let defaultERC20MakerAssetAddress: string;
- let defaultERC20TakerAssetAddress: string;
- let defaultERC721AssetAddress: string;
-
- let matchOrderTester: MatchOrderTester;
-
- let testExchange: TestExchangeInternalsContract;
-
- 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);
- erc721Wrapper = new ERC721Wrapper(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 token and proxy
- [erc721Token] = await erc721Wrapper.deployDummyTokensAsync();
- erc721Proxy = await erc721Wrapper.deployProxyAsync();
- await erc721Wrapper.setBalancesAndAllowancesAsync();
- const erc721Balances = await erc721Wrapper.getBalancesAsync();
- erc721LeftMakerAssetIds = erc721Balances[makerAddressLeft][erc721Token.address];
- erc721RightMakerAssetIds = erc721Balances[makerAddressRight][erc721Token.address];
- // Depoy exchange
- exchange = await ExchangeContract.deployFrom0xArtifactAsync(
- artifacts.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 and ERC721 trades by exchange
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc20Proxy.addAuthorizedAddress.sendTransactionAsync(exchange.address, {
- from: owner,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc721Proxy.addAuthorizedAddress.sendTransactionAsync(exchange.address, {
- from: owner,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
-
- reentrantErc20Token = await ReentrantERC20TokenContract.deployFrom0xArtifactAsync(
- artifacts.ReentrantERC20Token,
- provider,
- txDefaults,
- exchange.address,
- );
-
- // Set default addresses
- defaultERC20MakerAssetAddress = erc20TokenA.address;
- defaultERC20TakerAssetAddress = erc20TokenB.address;
- defaultERC721AssetAddress = erc721Token.address;
- // Create default order parameters
- const defaultOrderParamsLeft = {
- ...constants.STATIC_ORDER_PARAMS,
- makerAddress: makerAddressLeft,
- exchangeAddress: exchange.address,
- makerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
- takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
- feeRecipientAddress: feeRecipientAddressLeft,
- };
- const defaultOrderParamsRight = {
- ...constants.STATIC_ORDER_PARAMS,
- makerAddress: makerAddressRight,
- exchangeAddress: exchange.address,
- makerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
- takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
- feeRecipientAddress: feeRecipientAddressRight,
- };
- 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);
- // Set match order tester
- matchOrderTester = new MatchOrderTester(exchangeWrapper, erc20Wrapper, erc721Wrapper, zrxToken.address);
- testExchange = await TestExchangeInternalsContract.deployFrom0xArtifactAsync(
- artifacts.TestExchangeInternals,
- provider,
- txDefaults,
- );
- });
- beforeEach(async () => {
- await blockchainLifecycle.startAsync();
- });
- afterEach(async () => {
- await blockchainLifecycle.revertAsync();
- });
- describe('matchOrders', () => {
- beforeEach(async () => {
- erc20BalancesByOwner = await erc20Wrapper.getBalancesAsync();
- erc721TokenIdsByOwner = await erc721Wrapper.getBalancesAsync();
- });
-
- it('Should transfer correct amounts when right order is fully filled and values pass isRoundingErrorFloor but fail isRoundingErrorCeil', async () => {
- // Create orders to match
- const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
- makerAddress: makerAddressLeft,
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(17), 0),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(98), 0),
- feeRecipientAddress: feeRecipientAddressLeft,
- });
- const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
- makerAddress: makerAddressRight,
- makerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
- takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(75), 0),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(13), 0),
- feeRecipientAddress: feeRecipientAddressRight,
- });
- // Assert is rounding error ceil & not rounding error floor
- // These assertions are taken from MixinMatchOrders::calculateMatchedFillResults
- // The rounding error is derived computating how much the left maker will sell.
- const numerator = signedOrderLeft.makerAssetAmount;
- const denominator = signedOrderLeft.takerAssetAmount;
- const target = signedOrderRight.makerAssetAmount;
- const isRoundingErrorCeil = await testExchange.publicIsRoundingErrorCeil.callAsync(
- numerator,
- denominator,
- target,
- );
- expect(isRoundingErrorCeil).to.be.true();
- const isRoundingErrorFloor = await testExchange.publicIsRoundingErrorFloor.callAsync(
- numerator,
- denominator,
- target,
- );
- expect(isRoundingErrorFloor).to.be.false();
- // Match signedOrderLeft with signedOrderRight
- // Note that the left maker received a slightly better sell price.
- // This is intentional; see note in MixinMatchOrders.calculateMatchedFillResults.
- // Because the left maker received a slightly more favorable sell price, the fee
- // paid by the left taker is slightly higher than that paid by the left maker.
- // Fees can be thought of as a tax paid by the seller, derived from the sale price.
- 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%
- };
- await matchOrderTester.matchOrdersAndAssertEffectsAsync(
- signedOrderLeft,
- signedOrderRight,
- takerAddress,
- erc20BalancesByOwner,
- erc721TokenIdsByOwner,
- expectedTransferAmounts,
- );
- });
-
- it('Should transfer correct amounts when left order is fully filled and values pass isRoundingErrorCeil but fail isRoundingErrorFloor', async () => {
- // Create orders to match
- const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
- makerAddress: makerAddressLeft,
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(15), 0),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(90), 0),
- feeRecipientAddress: feeRecipientAddressLeft,
- });
- const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
- makerAddress: makerAddressRight,
- makerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
- takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(97), 0),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(14), 0),
- feeRecipientAddress: feeRecipientAddressRight,
- });
- // Assert is rounding error floor & not rounding error ceil
- // These assertions are taken from MixinMatchOrders::calculateMatchedFillResults
- // The rounding error is derived computating how much the right maker will buy.
- const numerator = signedOrderRight.takerAssetAmount;
- const denominator = signedOrderRight.makerAssetAmount;
- const target = signedOrderLeft.takerAssetAmount;
- const isRoundingErrorFloor = await testExchange.publicIsRoundingErrorFloor.callAsync(
- numerator,
- denominator,
- target,
- );
- expect(isRoundingErrorFloor).to.be.true();
- const isRoundingErrorCeil = await testExchange.publicIsRoundingErrorCeil.callAsync(
- numerator,
- denominator,
- target,
- );
- expect(isRoundingErrorCeil).to.be.false();
- // Match signedOrderLeft with signedOrderRight
- // Note that the right maker received a slightly better purchase price.
- // This is intentional; see note in MixinMatchOrders.calculateMatchedFillResults.
- // Because the right maker received a slightly more favorable buy price, the fee
- // paid by the right taker is slightly higher than that paid by the right maker.
- // Fees can be thought of as a tax paid by the seller, derived from the sale price.
- const expectedTransferAmounts = {
- // Left Maker
- amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(15), 0),
- amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(90), 0),
- feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Right Maker
- amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(90), 0),
- amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(13), 0),
- feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber('92.7835051546391752'), 16), // 92.78%
- // Taker
- amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 0),
- feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber('92.8571428571428571'), 16), // 92.85%
- };
- await matchOrderTester.matchOrdersAndAssertEffectsAsync(
- signedOrderLeft,
- signedOrderRight,
- takerAddress,
- erc20BalancesByOwner,
- erc721TokenIdsByOwner,
- expectedTransferAmounts,
- );
- });
-
- it('Should give right maker a better buy price when rounding', async () => {
- // Create orders to match
- const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
- makerAddress: makerAddressLeft,
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(16), 0),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(22), 0),
- feeRecipientAddress: feeRecipientAddressLeft,
- });
- const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
- makerAddress: makerAddressRight,
- makerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
- takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(83), 0),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(49), 0),
- feeRecipientAddress: feeRecipientAddressRight,
- });
- // Note:
- // The correct price buy price for the right maker would yield (49/83) * 22 = 12.988 units
- // of the left maker asset. This gets rounded up to 13, giving the right maker a better price.
- // Note:
- // The maker/taker fee percentage paid on the right order differs because
- // they received different sale prices. The right maker pays a
- // fee slightly lower than the right taker.
- const expectedTransferAmounts = {
- // Left Maker
- amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(16), 0),
- amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(22), 0),
- feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Right Maker
- amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(22), 0),
- amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(13), 0),
- feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber('26.5060240963855421'), 16), // 26.506%
- // Taker
- amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 0),
- feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber('26.5306122448979591'), 16), // 26.531%
- };
- // Match signedOrderLeft with signedOrderRight
- await matchOrderTester.matchOrdersAndAssertEffectsAsync(
- signedOrderLeft,
- signedOrderRight,
- takerAddress,
- erc20BalancesByOwner,
- erc721TokenIdsByOwner,
- expectedTransferAmounts,
- );
- });
-
- it('Should give left maker a better sell price when rounding', async () => {
- // Create orders to match
- const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
- makerAddress: makerAddressLeft,
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(12), 0),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(97), 0),
- feeRecipientAddress: feeRecipientAddressLeft,
- });
- const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
- makerAddress: makerAddressRight,
- makerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
- takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(89), 0),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 0),
- feeRecipientAddress: feeRecipientAddressRight,
- });
- // Note:
- // The maker/taker fee percentage paid on the left order differs because
- // they received different sale prices. The left maker pays a fee
- // slightly lower than the left taker.
- const expectedTransferAmounts = {
- // Left Maker
- amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(11), 0),
- amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(89), 0),
- feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber('91.6666666666666666'), 16), // 91.6%
- // Right Maker
- amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(89), 0),
- amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 0),
- feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Taker
- amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 0),
- feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber('91.7525773195876288'), 16), // 91.75%
- feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- };
- // Match signedOrderLeft with signedOrderRight
- await matchOrderTester.matchOrdersAndAssertEffectsAsync(
- signedOrderLeft,
- signedOrderRight,
- takerAddress,
- erc20BalancesByOwner,
- erc721TokenIdsByOwner,
- expectedTransferAmounts,
- );
- });
-
- it('Should give right maker and right taker a favorable fee price when rounding', async () => {
- // Create orders to match
- const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
- makerAddress: makerAddressLeft,
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(16), 0),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(22), 0),
- feeRecipientAddress: feeRecipientAddressLeft,
- });
- const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
- makerAddress: makerAddressRight,
- makerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
- takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(83), 0),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(49), 0),
- feeRecipientAddress: feeRecipientAddressRight,
- makerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(10000), 0),
- takerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(10000), 0),
- });
- // Note:
- // The maker/taker fee percentage paid on the right order differs because
- // they received different sale prices. The right maker pays a
- // fee slightly lower than the right taker.
- const expectedTransferAmounts = {
- // Left Maker
- amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(16), 0),
- amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(22), 0),
- feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Right Maker
- amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(22), 0),
- amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(13), 0),
- feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(2650), 0), // 2650.6 rounded down tro 2650
- // Taker
- amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 0),
- feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(2653), 0), // 2653.1 rounded down to 2653
- };
- // Match signedOrderLeft with signedOrderRight
- await matchOrderTester.matchOrdersAndAssertEffectsAsync(
- signedOrderLeft,
- signedOrderRight,
- takerAddress,
- erc20BalancesByOwner,
- erc721TokenIdsByOwner,
- expectedTransferAmounts,
- );
- });
-
- it('Should give left maker and left taker a favorable fee price when rounding', async () => {
- // Create orders to match
- const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
- makerAddress: makerAddressLeft,
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(12), 0),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(97), 0),
- feeRecipientAddress: feeRecipientAddressLeft,
- makerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(10000), 0),
- takerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(10000), 0),
- });
- const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
- makerAddress: makerAddressRight,
- makerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
- takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(89), 0),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 0),
- feeRecipientAddress: feeRecipientAddressRight,
- });
- // Note:
- // The maker/taker fee percentage paid on the left order differs because
- // they received different sale prices. The left maker pays a
- // fee slightly lower than the left taker.
- const expectedTransferAmounts = {
- // Left Maker
- amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(11), 0),
- amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(89), 0),
- feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(9166), 0), // 9166.6 rounded down to 9166
- // Right Maker
- amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(89), 0),
- amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 0),
- feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Taker
- amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 0),
- feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(9175), 0), // 9175.2 rounded down to 9175
- feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- };
- // Match signedOrderLeft with signedOrderRight
- await matchOrderTester.matchOrdersAndAssertEffectsAsync(
- signedOrderLeft,
- signedOrderRight,
- takerAddress,
- erc20BalancesByOwner,
- erc721TokenIdsByOwner,
- expectedTransferAmounts,
- );
- });
-
- it('Should transfer correct amounts when right order fill amount deviates from amount derived by `Exchange.fillOrder`', async () => {
- // Create orders to match
- const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
- makerAddress: makerAddressLeft,
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(1000), 0),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(1005), 0),
- feeRecipientAddress: feeRecipientAddressLeft,
- });
- const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
- makerAddress: makerAddressRight,
- makerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
- takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2126), 0),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(1063), 0),
- feeRecipientAddress: feeRecipientAddressRight,
- });
- const expectedTransferAmounts = {
- // Left Maker
- amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(1000), 0),
- amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(1005), 0),
- feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Right Maker
- // Notes:
- // i.
- // The left order is fully filled by the right order, so the right maker must sell 1005 units of their asset to the left maker.
- // By selling 1005 units, the right maker should theoretically receive 502.5 units of the left maker's asset.
- // Since the transfer amount must be an integer, this value must be rounded down to 502 or up to 503.
- // ii.
- // If the right order were filled via `Exchange.fillOrder` the respective fill amounts would be [1004, 502] or [1006, 503].
- // It follows that we cannot trigger a sale of 1005 units of the right maker's asset through `Exchange.fillOrder`.
- // iii.
- // For an optimal match, the algorithm must choose either [1005, 502] or [1005, 503] as fill amounts for the right order.
- // The algorithm favors the right maker when the exchange rate must be rounded, so the final fill for the right order is [1005, 503].
- // iv.
- // The right maker fee differs from the right taker fee because their exchange rate differs.
- // The right maker always receives the better exchange and fee price.
- amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(1005), 0),
- amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(503), 0),
- feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber('47.2718720602069614'), 16), // 47.27%
- // Taker
- amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(497), 0),
- feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber('47.3189087488240827'), 16), // 47.31%
- };
- // Match signedOrderLeft with signedOrderRight
- await matchOrderTester.matchOrdersAndAssertEffectsAsync(
- signedOrderLeft,
- signedOrderRight,
- takerAddress,
- erc20BalancesByOwner,
- erc721TokenIdsByOwner,
- expectedTransferAmounts,
- );
- });
-
- const reentrancyTest = (functionNames: string[]) => {
- _.forEach(functionNames, async (functionName: string, functionId: number) => {
- const description = `should not allow matchOrders to reenter the Exchange contract via ${functionName}`;
- it(description, async () => {
- const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
- makerAssetData: assetDataUtils.encodeERC20AssetData(reentrantErc20Token.address),
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- });
- const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
- makerAddress: makerAddressRight,
- takerAssetData: assetDataUtils.encodeERC20AssetData(reentrantErc20Token.address),
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
- feeRecipientAddress: feeRecipientAddressRight,
- });
- await web3Wrapper.awaitTransactionSuccessAsync(
- await reentrantErc20Token.setCurrentFunction.sendTransactionAsync(functionId),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await expectTransactionFailedAsync(
- exchangeWrapper.matchOrdersAsync(signedOrderLeft, signedOrderRight, takerAddress),
- RevertReason.TransferFailed,
- );
- });
- });
- };
- describe('matchOrders reentrancy tests', () => reentrancyTest(constants.FUNCTIONS_WITH_MUTEX));
-
- 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: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
- amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Right Maker
- amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
- feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Taker
- amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 18),
- feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- };
- await matchOrderTester.matchOrdersAndAssertEffectsAsync(
- signedOrderLeft,
- signedOrderRight,
- takerAddress,
- erc20BalancesByOwner,
- erc721TokenIdsByOwner,
- expectedTransferAmounts,
- );
- });
-
- 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: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
- amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Right Maker
- amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
- feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Taker
- amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(0), 18),
- feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- };
- // Match signedOrderLeft with signedOrderRight
- await matchOrderTester.matchOrdersAndAssertEffectsAsync(
- signedOrderLeft,
- signedOrderRight,
- takerAddress,
- erc20BalancesByOwner,
- erc721TokenIdsByOwner,
- expectedTransferAmounts,
- );
- });
-
- it('should transfer the correct amounts when left order is completely filled and right order is 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: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
- amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Right Maker
- amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
- feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(50), 16), // 50%
- // Taker
- amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 18),
- feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(50), 16), // 50%
- };
- // Match signedOrderLeft with signedOrderRight
- await matchOrderTester.matchOrdersAndAssertEffectsAsync(
- signedOrderLeft,
- signedOrderRight,
- takerAddress,
- erc20BalancesByOwner,
- erc721TokenIdsByOwner,
- expectedTransferAmounts,
- );
- });
-
- it('should transfer the correct amounts when right order is completely filled and left order is partially filled', async () => {
- // Create orders to match
- const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(50), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 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: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
- amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 16), // 10%
- // Right Maker
- amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
- feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Taker
- amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 18),
- feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 16), // 10%
- feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- };
- // Match signedOrderLeft with signedOrderRight
- await matchOrderTester.matchOrdersAndAssertEffectsAsync(
- signedOrderLeft,
- signedOrderRight,
- takerAddress,
- erc20BalancesByOwner,
- erc721TokenIdsByOwner,
- expectedTransferAmounts,
- );
- });
-
- it('should transfer the correct amounts when consecutive calls are used to completely fill the left order', async () => {
- // Create orders to match
- const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(50), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18),
- });
- const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
- });
- // Match orders
- let newERC20BalancesByOwner: ERC20BalancesByOwner;
- let newERC721TokenIdsByOwner: ERC721TokenIdsByOwner;
- const expectedTransferAmounts = {
- // Left Maker
- amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
- amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 16), // 10%
- // Right Maker
- amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
- feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Taker
- amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 18),
- feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 16), // 10%
- feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- };
- // prettier-ignore
- [
- newERC20BalancesByOwner,
- // tslint:disable-next-line:trailing-comma
- newERC721TokenIdsByOwner
- ] = await matchOrderTester.matchOrdersAndAssertEffectsAsync(
- signedOrderLeft,
- signedOrderRight,
- takerAddress,
- erc20BalancesByOwner,
- erc721TokenIdsByOwner,
- expectedTransferAmounts,
- );
- // Construct second right order
- // Note: This order needs makerAssetAmount=90/takerAssetAmount=[anything <= 45] to fully fill the right order.
- // However, we use 100/50 to ensure a partial fill as we want to go down the "left fill"
- // branch in the contract twice for this test.
- const signedOrderRight2 = await orderFactoryRight.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(50), 18),
- });
- // Match signedOrderLeft with signedOrderRight2
- const leftTakerAssetFilledAmount = signedOrderRight.makerAssetAmount;
- const rightTakerAssetFilledAmount = new BigNumber(0);
- const expectedTransferAmounts2 = {
- // Left Maker
- amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(45), 18),
- amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(90), 18),
- feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(90), 16), // 90% (10% paid earlier)
- // Right Maker
- amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(90), 18),
- amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(45), 18),
- feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(90), 16), // 90%
- // Taker
- amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(0), 18),
- feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(90), 16), // 90% (10% paid earlier)
- feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(90), 16), // 90%
- };
- await matchOrderTester.matchOrdersAndAssertEffectsAsync(
- signedOrderLeft,
- signedOrderRight2,
- takerAddress,
- newERC20BalancesByOwner,
- newERC721TokenIdsByOwner,
- expectedTransferAmounts2,
- leftTakerAssetFilledAmount,
- rightTakerAssetFilledAmount,
- );
- });
-
- it('should transfer the correct amounts when consecutive calls are used to completely fill the right order', async () => {
- // Create orders to match
- const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
- });
-
- const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(50), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18),
- });
- // Match orders
- let newERC20BalancesByOwner: ERC20BalancesByOwner;
- let newERC721TokenIdsByOwner: ERC721TokenIdsByOwner;
- const expectedTransferAmounts = {
- // Left Maker
- amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
- feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Right Maker
- amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
- amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(4), 18),
- feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(4), 16), // 4%
- // Taker
- amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(6), 18),
- feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(4), 16), // 4%
- };
- // prettier-ignore
- [
- newERC20BalancesByOwner,
- // tslint:disable-next-line:trailing-comma
- newERC721TokenIdsByOwner
- ] = await matchOrderTester.matchOrdersAndAssertEffectsAsync(
- signedOrderLeft,
- signedOrderRight,
- takerAddress,
- erc20BalancesByOwner,
- erc721TokenIdsByOwner,
- expectedTransferAmounts,
- );
-
- // Create second left order
- // Note: This order needs makerAssetAmount=96/takerAssetAmount=48 to fully fill the right order.
- // However, we use 100/50 to ensure a partial fill as we want to go down the "right fill"
- // branch in the contract twice for this test.
- const signedOrderLeft2 = await orderFactoryLeft.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(50), 18),
- });
- // Match signedOrderLeft2 with signedOrderRight
- const leftTakerAssetFilledAmount = new BigNumber(0);
- const takerAmountReceived = newERC20BalancesByOwner[takerAddress][defaultERC20MakerAssetAddress].minus(
- erc20BalancesByOwner[takerAddress][defaultERC20MakerAssetAddress],
- );
- const rightTakerAssetFilledAmount = signedOrderLeft.makerAssetAmount.minus(takerAmountReceived);
- const expectedTransferAmounts2 = {
- // Left Maker
- amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(96), 18),
- amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(48), 18),
- feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(96), 16), // 96%
- // Right Maker
- amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(48), 18),
- amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(96), 18),
- feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(96), 16), // 96%
- // Taker
- amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(0), 18),
- feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(96), 16), // 96%
- feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(96), 16), // 96%
- };
- await matchOrderTester.matchOrdersAndAssertEffectsAsync(
- signedOrderLeft2,
- signedOrderRight,
- takerAddress,
- newERC20BalancesByOwner,
- newERC721TokenIdsByOwner,
- expectedTransferAmounts2,
- leftTakerAssetFilledAmount,
- rightTakerAssetFilledAmount,
- );
- });
-
- it('should transfer the correct amounts if fee recipient is the same across both matched orders', async () => {
- const feeRecipientAddress = feeRecipientAddressLeft;
- const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- feeRecipientAddress,
- });
- const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
- feeRecipientAddress,
- });
- // Match orders
- const expectedTransferAmounts = {
- // Left Maker
- amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
- amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Right Maker
- amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
- feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Taker
- amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 18),
- feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- };
- await matchOrderTester.matchOrdersAndAssertEffectsAsync(
- signedOrderLeft,
- signedOrderRight,
- takerAddress,
- erc20BalancesByOwner,
- erc721TokenIdsByOwner,
- expectedTransferAmounts,
- );
- });
-
- it('should transfer the correct amounts if taker is also the left order maker', 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 orders
- takerAddress = signedOrderLeft.makerAddress;
- const expectedTransferAmounts = {
- // Left Maker
- amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
- amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Right Maker
- amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
- feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Taker
- amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 18),
- feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- };
- await matchOrderTester.matchOrdersAndAssertEffectsAsync(
- signedOrderLeft,
- signedOrderRight,
- takerAddress,
- erc20BalancesByOwner,
- erc721TokenIdsByOwner,
- expectedTransferAmounts,
- );
- });
-
- it('should transfer the correct amounts if taker is also the right order maker', 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 orders
- takerAddress = signedOrderRight.makerAddress;
- const expectedTransferAmounts = {
- // Left Maker
- amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
- amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Right Maker
- amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
- feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Taker
- amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 18),
- feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- };
- await matchOrderTester.matchOrdersAndAssertEffectsAsync(
- signedOrderLeft,
- signedOrderRight,
- takerAddress,
- erc20BalancesByOwner,
- erc721TokenIdsByOwner,
- expectedTransferAmounts,
- );
- });
-
- it('should transfer the correct amounts if taker is also the left fee recipient', 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 orders
- takerAddress = feeRecipientAddressLeft;
- const expectedTransferAmounts = {
- // Left Maker
- amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
- amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Right Maker
- amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
- feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Taker
- amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 18),
- feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- };
- await matchOrderTester.matchOrdersAndAssertEffectsAsync(
- signedOrderLeft,
- signedOrderRight,
- takerAddress,
- erc20BalancesByOwner,
- erc721TokenIdsByOwner,
- expectedTransferAmounts,
- );
- });
-
- it('should transfer the correct amounts if taker is also the right fee recipient', 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 orders
- takerAddress = feeRecipientAddressRight;
- const expectedTransferAmounts = {
- // Left Maker
- amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
- amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Right Maker
- amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
- feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Taker
- amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 18),
- feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- };
- await matchOrderTester.matchOrdersAndAssertEffectsAsync(
- signedOrderLeft,
- signedOrderRight,
- takerAddress,
- erc20BalancesByOwner,
- erc721TokenIdsByOwner,
- expectedTransferAmounts,
- );
- });
-
- it('should transfer the correct amounts if left maker is the left fee recipient and right maker is the right fee recipient', 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 orders
- const expectedTransferAmounts = {
- // Left Maker
- amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
- amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Right Maker
- amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
- feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Taker
- amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 18),
- feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- };
- await matchOrderTester.matchOrdersAndAssertEffectsAsync(
- signedOrderLeft,
- signedOrderRight,
- takerAddress,
- erc20BalancesByOwner,
- erc721TokenIdsByOwner,
- expectedTransferAmounts,
- );
- });
-
- it('Should throw if left order is not fillable', 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),
- });
- // Cancel left order
- await exchangeWrapper.cancelOrderAsync(signedOrderLeft, signedOrderLeft.makerAddress);
- // Match orders
- return expectTransactionFailedAsync(
- exchangeWrapper.matchOrdersAsync(signedOrderLeft, signedOrderRight, takerAddress),
- RevertReason.OrderUnfillable,
- );
- });
-
- it('Should throw if right order is not fillable', 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),
- });
- // Cancel right order
- await exchangeWrapper.cancelOrderAsync(signedOrderRight, signedOrderRight.makerAddress);
- // Match orders
- return expectTransactionFailedAsync(
- exchangeWrapper.matchOrdersAsync(signedOrderLeft, signedOrderRight, takerAddress),
- RevertReason.OrderUnfillable,
- );
- });
-
- it('should throw if there is not a positive spread', async () => {
- // Create orders to match
- const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18),
- });
- const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(200), 18),
- });
- // Match orders
- return expectTransactionFailedAsync(
- exchangeWrapper.matchOrdersAsync(signedOrderLeft, signedOrderRight, takerAddress),
- RevertReason.NegativeSpreadRequired,
- );
- });
-
- it('should throw if the left maker asset is not equal to the right taker asset ', 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({
- takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
- });
- // Match orders
- return expectTransactionFailedAsync(
- exchangeWrapper.matchOrdersAsync(signedOrderLeft, signedOrderRight, takerAddress),
- // We are assuming assetData fields of the right order are the
- // reverse of the left order, rather than checking equality. This
- // saves a bunch of gas, but as a result if the assetData fields are
- // off then the failure ends up happening at signature validation
- RevertReason.InvalidOrderSignature,
- );
- });
-
- it('should throw if the right maker asset is not equal to the left taker asset', async () => {
- // Create orders to match
- const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
- takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
- 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 orders
- return expectTransactionFailedAsync(
- exchangeWrapper.matchOrdersAsync(signedOrderLeft, signedOrderRight, takerAddress),
- RevertReason.InvalidOrderSignature,
- );
- });
-
- it('should transfer correct amounts when left order maker asset is an ERC721 token', async () => {
- // Create orders to match
- const erc721TokenToTransfer = erc721LeftMakerAssetIds[0];
- const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
- makerAssetData: assetDataUtils.encodeERC721AssetData(defaultERC721AssetAddress, erc721TokenToTransfer),
- makerAssetAmount: new BigNumber(1),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- });
- const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
- takerAssetData: assetDataUtils.encodeERC721AssetData(defaultERC721AssetAddress, erc721TokenToTransfer),
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- takerAssetAmount: new BigNumber(1),
- });
- // Match orders
- const expectedTransferAmounts = {
- // Left Maker
- amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 0),
- amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Right Maker
- amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 0),
- feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Taker
- amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(0), 18),
- feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 50%
- };
- await matchOrderTester.matchOrdersAndAssertEffectsAsync(
- signedOrderLeft,
- signedOrderRight,
- takerAddress,
- erc20BalancesByOwner,
- erc721TokenIdsByOwner,
- expectedTransferAmounts,
- );
- });
-
- it('should transfer correct amounts when right order maker asset is an ERC721 token', async () => {
- // Create orders to match
- const erc721TokenToTransfer = erc721RightMakerAssetIds[0];
- const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
- takerAssetData: assetDataUtils.encodeERC721AssetData(defaultERC721AssetAddress, erc721TokenToTransfer),
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- takerAssetAmount: new BigNumber(1),
- });
- const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
- makerAssetData: assetDataUtils.encodeERC721AssetData(defaultERC721AssetAddress, erc721TokenToTransfer),
- makerAssetAmount: new BigNumber(1),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(8), 18),
- });
- // Match orders
- const expectedTransferAmounts = {
- // Left Maker
- amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 0),
- feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Right Maker
- amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 0),
- amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(8), 18),
- feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Taker
- amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
- feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- };
- await matchOrderTester.matchOrdersAndAssertEffectsAsync(
- signedOrderLeft,
- signedOrderRight,
- takerAddress,
- erc20BalancesByOwner,
- erc721TokenIdsByOwner,
- expectedTransferAmounts,
- );
- });
- });
-}); // tslint:disable-line:max-file-line-count
diff --git a/packages/contracts/test/exchange/signature_validator.ts b/packages/contracts/test/exchange/signature_validator.ts
deleted file mode 100644
index 756c72766..000000000
--- a/packages/contracts/test/exchange/signature_validator.ts
+++ /dev/null
@@ -1,522 +0,0 @@
-import { BlockchainLifecycle } from '@0x/dev-utils';
-import { assetDataUtils, orderHashUtils, signatureUtils } from '@0x/order-utils';
-import { RevertReason, SignatureType, SignedOrder } from '@0x/types';
-import * as chai from 'chai';
-import { LogWithDecodedArgs } from 'ethereum-types';
-import ethUtil = require('ethereumjs-util');
-
-import {
- TestSignatureValidatorContract,
- TestSignatureValidatorSignatureValidatorApprovalEventArgs,
-} from '../../generated-wrappers/test_signature_validator';
-import { TestStaticCallReceiverContract } from '../../generated-wrappers/test_static_call_receiver';
-import { ValidatorContract } from '../../generated-wrappers/validator';
-import { WalletContract } from '../../generated-wrappers/wallet';
-import { artifacts } from '../../src/artifacts';
-import { addressUtils } from '../utils/address_utils';
-import { expectContractCallFailedAsync } from '../utils/assertions';
-import { chaiSetup } from '../utils/chai_setup';
-import { constants } from '../utils/constants';
-import { LogDecoder } from '../utils/log_decoder';
-import { OrderFactory } from '../utils/order_factory';
-import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper';
-
-chaiSetup.configure();
-const expect = chai.expect;
-
-const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
-// tslint:disable:no-unnecessary-type-assertion
-describe('MixinSignatureValidator', () => {
- let signedOrder: SignedOrder;
- let orderFactory: OrderFactory;
- let signatureValidator: TestSignatureValidatorContract;
- let testWallet: WalletContract;
- let testValidator: ValidatorContract;
- let maliciousWallet: TestStaticCallReceiverContract;
- let maliciousValidator: TestStaticCallReceiverContract;
- let signerAddress: string;
- let signerPrivateKey: Buffer;
- let notSignerAddress: string;
- let notSignerPrivateKey: Buffer;
- let signatureValidatorLogDecoder: LogDecoder;
-
- before(async () => {
- await blockchainLifecycle.startAsync();
- });
- after(async () => {
- await blockchainLifecycle.revertAsync();
- });
- before(async () => {
- const accounts = await web3Wrapper.getAvailableAddressesAsync();
- const makerAddress = accounts[0];
- signerAddress = makerAddress;
- notSignerAddress = accounts[1];
- signatureValidator = await TestSignatureValidatorContract.deployFrom0xArtifactAsync(
- artifacts.TestSignatureValidator,
- provider,
- txDefaults,
- );
- testWallet = await WalletContract.deployFrom0xArtifactAsync(
- artifacts.Wallet,
- provider,
- txDefaults,
- signerAddress,
- );
- testValidator = await ValidatorContract.deployFrom0xArtifactAsync(
- artifacts.Validator,
- provider,
- txDefaults,
- signerAddress,
- );
- maliciousWallet = maliciousValidator = await TestStaticCallReceiverContract.deployFrom0xArtifactAsync(
- artifacts.TestStaticCallReceiver,
- provider,
- txDefaults,
- );
- signatureValidatorLogDecoder = new LogDecoder(web3Wrapper);
- await web3Wrapper.awaitTransactionSuccessAsync(
- await signatureValidator.setSignatureValidatorApproval.sendTransactionAsync(testValidator.address, true, {
- from: signerAddress,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await signatureValidator.setSignatureValidatorApproval.sendTransactionAsync(
- maliciousValidator.address,
- true,
- {
- from: signerAddress,
- },
- ),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
-
- const defaultOrderParams = {
- ...constants.STATIC_ORDER_PARAMS,
- exchangeAddress: signatureValidator.address,
- makerAddress,
- feeRecipientAddress: addressUtils.generatePseudoRandomAddress(),
- makerAssetData: assetDataUtils.encodeERC20AssetData(addressUtils.generatePseudoRandomAddress()),
- takerAssetData: assetDataUtils.encodeERC20AssetData(addressUtils.generatePseudoRandomAddress()),
- };
- signerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddress)];
- notSignerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(notSignerAddress)];
- orderFactory = new OrderFactory(signerPrivateKey, defaultOrderParams);
- });
-
- beforeEach(async () => {
- await blockchainLifecycle.startAsync();
- });
- afterEach(async () => {
- await blockchainLifecycle.revertAsync();
- });
-
- describe('isValidSignature', () => {
- beforeEach(async () => {
- signedOrder = await orderFactory.newSignedOrderAsync();
- });
-
- it('should revert when signature is empty', async () => {
- const emptySignature = '0x';
- const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
- return expectContractCallFailedAsync(
- signatureValidator.publicIsValidSignature.callAsync(
- orderHashHex,
- signedOrder.makerAddress,
- emptySignature,
- ),
- RevertReason.LengthGreaterThan0Required,
- );
- });
-
- it('should revert when signature type is unsupported', async () => {
- const unsupportedSignatureType = SignatureType.NSignatureTypes;
- const unsupportedSignatureHex = '0x' + Buffer.from([unsupportedSignatureType]).toString('hex');
- const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
- return expectContractCallFailedAsync(
- signatureValidator.publicIsValidSignature.callAsync(
- orderHashHex,
- signedOrder.makerAddress,
- unsupportedSignatureHex,
- ),
- RevertReason.SignatureUnsupported,
- );
- });
-
- it('should revert when SignatureType=Illegal', async () => {
- const unsupportedSignatureHex = '0x' + Buffer.from([SignatureType.Illegal]).toString('hex');
- const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
- return expectContractCallFailedAsync(
- signatureValidator.publicIsValidSignature.callAsync(
- orderHashHex,
- signedOrder.makerAddress,
- unsupportedSignatureHex,
- ),
- RevertReason.SignatureIllegal,
- );
- });
-
- it('should return false when SignatureType=Invalid and signature has a length of zero', async () => {
- const signatureHex = '0x' + Buffer.from([SignatureType.Invalid]).toString('hex');
- const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
- const isValidSignature = await signatureValidator.publicIsValidSignature.callAsync(
- orderHashHex,
- signedOrder.makerAddress,
- signatureHex,
- );
- expect(isValidSignature).to.be.false();
- });
-
- it('should revert when SignatureType=Invalid and signature length is non-zero', async () => {
- const fillerData = ethUtil.toBuffer('0xdeadbeef');
- const signatureType = ethUtil.toBuffer(`0x${SignatureType.Invalid}`);
- const signatureBuffer = Buffer.concat([fillerData, signatureType]);
- const signatureHex = ethUtil.bufferToHex(signatureBuffer);
- const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
- return expectContractCallFailedAsync(
- signatureValidator.publicIsValidSignature.callAsync(
- orderHashHex,
- signedOrder.makerAddress,
- signatureHex,
- ),
- RevertReason.Length0Required,
- );
- });
-
- it('should return true when SignatureType=EIP712 and signature is valid', async () => {
- // Create EIP712 signature
- const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
- const orderHashBuffer = ethUtil.toBuffer(orderHashHex);
- const ecSignature = ethUtil.ecsign(orderHashBuffer, signerPrivateKey);
- // Create 0x signature from EIP712 signature
- const signature = Buffer.concat([
- ethUtil.toBuffer(ecSignature.v),
- ecSignature.r,
- ecSignature.s,
- ethUtil.toBuffer(`0x${SignatureType.EIP712}`),
- ]);
- const signatureHex = ethUtil.bufferToHex(signature);
- // Validate signature
- const isValidSignature = await signatureValidator.publicIsValidSignature.callAsync(
- orderHashHex,
- signerAddress,
- signatureHex,
- );
- expect(isValidSignature).to.be.true();
- });
-
- it('should return false when SignatureType=EIP712 and signature is invalid', async () => {
- // Create EIP712 signature
- const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
- const orderHashBuffer = ethUtil.toBuffer(orderHashHex);
- const ecSignature = ethUtil.ecsign(orderHashBuffer, signerPrivateKey);
- // Create 0x signature from EIP712 signature
- const signature = Buffer.concat([
- ethUtil.toBuffer(ecSignature.v),
- ecSignature.r,
- ecSignature.s,
- ethUtil.toBuffer(`0x${SignatureType.EIP712}`),
- ]);
- const signatureHex = ethUtil.bufferToHex(signature);
- // Validate signature.
- // This will fail because `signerAddress` signed the message, but we're passing in `notSignerAddress`
- const isValidSignature = await signatureValidator.publicIsValidSignature.callAsync(
- orderHashHex,
- notSignerAddress,
- signatureHex,
- );
- expect(isValidSignature).to.be.false();
- });
-
- it('should return true when SignatureType=EthSign and signature is valid', async () => {
- // Create EthSign signature
- const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
- const orderHashWithEthSignPrefixHex = signatureUtils.addSignedMessagePrefix(orderHashHex);
- const orderHashWithEthSignPrefixBuffer = ethUtil.toBuffer(orderHashWithEthSignPrefixHex);
- const ecSignature = ethUtil.ecsign(orderHashWithEthSignPrefixBuffer, signerPrivateKey);
- // Create 0x signature from EthSign signature
- const signature = Buffer.concat([
- ethUtil.toBuffer(ecSignature.v),
- ecSignature.r,
- ecSignature.s,
- ethUtil.toBuffer(`0x${SignatureType.EthSign}`),
- ]);
- const signatureHex = ethUtil.bufferToHex(signature);
- // Validate signature
- const isValidSignature = await signatureValidator.publicIsValidSignature.callAsync(
- orderHashHex,
- signerAddress,
- signatureHex,
- );
- expect(isValidSignature).to.be.true();
- });
-
- it('should return false when SignatureType=EthSign and signature is invalid', async () => {
- // Create EthSign signature
- const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
- const orderHashWithEthSignPrefixHex = signatureUtils.addSignedMessagePrefix(orderHashHex);
- const orderHashWithEthSignPrefixBuffer = ethUtil.toBuffer(orderHashWithEthSignPrefixHex);
- const ecSignature = ethUtil.ecsign(orderHashWithEthSignPrefixBuffer, signerPrivateKey);
- // Create 0x signature from EthSign signature
- const signature = Buffer.concat([
- ethUtil.toBuffer(ecSignature.v),
- ecSignature.r,
- ecSignature.s,
- ethUtil.toBuffer(`0x${SignatureType.EthSign}`),
- ]);
- const signatureHex = ethUtil.bufferToHex(signature);
- // Validate signature.
- // This will fail because `signerAddress` signed the message, but we're passing in `notSignerAddress`
- const isValidSignature = await signatureValidator.publicIsValidSignature.callAsync(
- orderHashHex,
- notSignerAddress,
- signatureHex,
- );
- expect(isValidSignature).to.be.false();
- });
-
- it('should return true when SignatureType=Wallet and signature is valid', async () => {
- // Create EIP712 signature
- const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
- const orderHashBuffer = ethUtil.toBuffer(orderHashHex);
- const ecSignature = ethUtil.ecsign(orderHashBuffer, signerPrivateKey);
- // Create 0x signature from EIP712 signature
- const signature = Buffer.concat([
- ethUtil.toBuffer(ecSignature.v),
- ecSignature.r,
- ecSignature.s,
- ethUtil.toBuffer(`0x${SignatureType.Wallet}`),
- ]);
- const signatureHex = ethUtil.bufferToHex(signature);
- // Validate signature
- const isValidSignature = await signatureValidator.publicIsValidSignature.callAsync(
- orderHashHex,
- testWallet.address,
- signatureHex,
- );
- expect(isValidSignature).to.be.true();
- });
-
- it('should return false when SignatureType=Wallet and signature is invalid', async () => {
- // Create EIP712 signature using a private key that does not belong to the wallet owner.
- const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
- const orderHashBuffer = ethUtil.toBuffer(orderHashHex);
- const notWalletOwnerPrivateKey = notSignerPrivateKey;
- const ecSignature = ethUtil.ecsign(orderHashBuffer, notWalletOwnerPrivateKey);
- // Create 0x signature from EIP712 signature
- const signature = Buffer.concat([
- ethUtil.toBuffer(ecSignature.v),
- ecSignature.r,
- ecSignature.s,
- ethUtil.toBuffer(`0x${SignatureType.Wallet}`),
- ]);
- const signatureHex = ethUtil.bufferToHex(signature);
- // Validate signature
- const isValidSignature = await signatureValidator.publicIsValidSignature.callAsync(
- orderHashHex,
- testWallet.address,
- signatureHex,
- );
- expect(isValidSignature).to.be.false();
- });
-
- it('should revert when `isValidSignature` attempts to update state and SignatureType=Wallet', async () => {
- // Create EIP712 signature
- const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
- const orderHashBuffer = ethUtil.toBuffer(orderHashHex);
- const ecSignature = ethUtil.ecsign(orderHashBuffer, signerPrivateKey);
- // Create 0x signature from EIP712 signature
- const signature = Buffer.concat([
- ethUtil.toBuffer(ecSignature.v),
- ecSignature.r,
- ecSignature.s,
- ethUtil.toBuffer(`0x${SignatureType.Wallet}`),
- ]);
- const signatureHex = ethUtil.bufferToHex(signature);
- await expectContractCallFailedAsync(
- signatureValidator.publicIsValidSignature.callAsync(
- orderHashHex,
- maliciousWallet.address,
- signatureHex,
- ),
- RevertReason.WalletError,
- );
- });
-
- it('should return true when SignatureType=Validator, signature is valid and validator is approved', async () => {
- const validatorAddress = ethUtil.toBuffer(`${testValidator.address}`);
- const signatureType = ethUtil.toBuffer(`0x${SignatureType.Validator}`);
- const signature = Buffer.concat([validatorAddress, signatureType]);
- const signatureHex = ethUtil.bufferToHex(signature);
- const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
- const isValidSignature = await signatureValidator.publicIsValidSignature.callAsync(
- orderHashHex,
- signerAddress,
- signatureHex,
- );
- expect(isValidSignature).to.be.true();
- });
-
- it('should return false when SignatureType=Validator, signature is invalid and validator is approved', async () => {
- const validatorAddress = ethUtil.toBuffer(`${testValidator.address}`);
- const signatureType = ethUtil.toBuffer(`0x${SignatureType.Validator}`);
- const signature = Buffer.concat([validatorAddress, signatureType]);
- const signatureHex = ethUtil.bufferToHex(signature);
- const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
- // This will return false because we signed the message with `signerAddress`, but
- // are validating against `notSignerAddress`
- const isValidSignature = await signatureValidator.publicIsValidSignature.callAsync(
- orderHashHex,
- notSignerAddress,
- signatureHex,
- );
- expect(isValidSignature).to.be.false();
- });
-
- it('should revert when `isValidSignature` attempts to update state and SignatureType=Validator', async () => {
- const validatorAddress = ethUtil.toBuffer(`${maliciousValidator.address}`);
- const signatureType = ethUtil.toBuffer(`0x${SignatureType.Validator}`);
- const signature = Buffer.concat([validatorAddress, signatureType]);
- const signatureHex = ethUtil.bufferToHex(signature);
- const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
- await expectContractCallFailedAsync(
- signatureValidator.publicIsValidSignature.callAsync(orderHashHex, signerAddress, signatureHex),
- RevertReason.ValidatorError,
- );
- });
- it('should return false when SignatureType=Validator, signature is valid and validator is not approved', async () => {
- // Set approval of signature validator to false
- await web3Wrapper.awaitTransactionSuccessAsync(
- await signatureValidator.setSignatureValidatorApproval.sendTransactionAsync(
- testValidator.address,
- false,
- { from: signerAddress },
- ),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- // Validate signature
- const validatorAddress = ethUtil.toBuffer(`${testValidator.address}`);
- const signatureType = ethUtil.toBuffer(`0x${SignatureType.Validator}`);
- const signature = Buffer.concat([validatorAddress, signatureType]);
- const signatureHex = ethUtil.bufferToHex(signature);
- const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
- const isValidSignature = await signatureValidator.publicIsValidSignature.callAsync(
- orderHashHex,
- signerAddress,
- signatureHex,
- );
- expect(isValidSignature).to.be.false();
- });
-
- it('should return true when SignatureType=Presigned and signer has presigned hash', async () => {
- // Presign hash
- const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
- await web3Wrapper.awaitTransactionSuccessAsync(
- await signatureValidator.preSign.sendTransactionAsync(
- orderHashHex,
- signedOrder.makerAddress,
- signedOrder.signature,
- ),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- // Validate presigned signature
- const signature = ethUtil.toBuffer(`0x${SignatureType.PreSigned}`);
- const signatureHex = ethUtil.bufferToHex(signature);
- const isValidSignature = await signatureValidator.publicIsValidSignature.callAsync(
- orderHashHex,
- signedOrder.makerAddress,
- signatureHex,
- );
- expect(isValidSignature).to.be.true();
- });
-
- it('should return false when SignatureType=Presigned and signer has not presigned hash', async () => {
- const signature = ethUtil.toBuffer(`0x${SignatureType.PreSigned}`);
- const signatureHex = ethUtil.bufferToHex(signature);
- const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
- const isValidSignature = await signatureValidator.publicIsValidSignature.callAsync(
- orderHashHex,
- signedOrder.makerAddress,
- signatureHex,
- );
- expect(isValidSignature).to.be.false();
- });
-
- it('should return true when message was signed by a Trezor One (firmware version 1.6.2)', async () => {
- // messageHash translates to 0x2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b
- const messageHash = ethUtil.bufferToHex(ethUtil.toBuffer('++++++++++++++++++++++++++++++++'));
- const signer = '0xc28b145f10f0bcf0fc000e778615f8fd73490bad';
- const v = ethUtil.toBuffer('0x1c');
- const r = ethUtil.toBuffer('0x7b888b596ccf87f0bacab0dcb483124973f7420f169b4824d7a12534ac1e9832');
- const s = ethUtil.toBuffer('0x0c8e14f7edc01459e13965f1da56e0c23ed11e2cca932571eee1292178f90424');
- const trezorSignatureType = ethUtil.toBuffer(`0x${SignatureType.EthSign}`);
- const signature = Buffer.concat([v, r, s, trezorSignatureType]);
- const signatureHex = ethUtil.bufferToHex(signature);
- const isValidSignature = await signatureValidator.publicIsValidSignature.callAsync(
- messageHash,
- signer,
- signatureHex,
- );
- expect(isValidSignature).to.be.true();
- });
-
- it('should return true when message was signed by a Trezor Model T (firmware version 2.0.7)', async () => {
- // messageHash translates to 0x2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b
- const messageHash = ethUtil.bufferToHex(ethUtil.toBuffer('++++++++++++++++++++++++++++++++'));
- const signer = '0x98ce6d9345e8ffa7d99ee0822272fae9d2c0e895';
- const v = ethUtil.toBuffer('0x1c');
- const r = ethUtil.toBuffer('0x423b71062c327f0ec4fe199b8da0f34185e59b4c1cb4cc23df86cac4a601fb3f');
- const s = ethUtil.toBuffer('0x53810d6591b5348b7ee08ee812c874b0fdfb942c9849d59512c90e295221091f');
- const trezorSignatureType = ethUtil.toBuffer(`0x${SignatureType.EthSign}`);
- const signature = Buffer.concat([v, r, s, trezorSignatureType]);
- const signatureHex = ethUtil.bufferToHex(signature);
- const isValidSignature = await signatureValidator.publicIsValidSignature.callAsync(
- messageHash,
- signer,
- signatureHex,
- );
- expect(isValidSignature).to.be.true();
- });
- });
-
- describe('setSignatureValidatorApproval', () => {
- it('should emit a SignatureValidatorApprovalSet with correct args when a validator is approved', async () => {
- const approval = true;
- const res = await signatureValidatorLogDecoder.getTxWithDecodedLogsAsync(
- await signatureValidator.setSignatureValidatorApproval.sendTransactionAsync(
- testValidator.address,
- approval,
- {
- from: signerAddress,
- },
- ),
- );
- expect(res.logs.length).to.equal(1);
- const log = res.logs[0] as LogWithDecodedArgs<TestSignatureValidatorSignatureValidatorApprovalEventArgs>;
- const logArgs = log.args;
- expect(logArgs.signerAddress).to.equal(signerAddress);
- expect(logArgs.validatorAddress).to.equal(testValidator.address);
- expect(logArgs.approved).to.equal(approval);
- });
- it('should emit a SignatureValidatorApprovalSet with correct args when a validator is disapproved', async () => {
- const approval = false;
- const res = await signatureValidatorLogDecoder.getTxWithDecodedLogsAsync(
- await signatureValidator.setSignatureValidatorApproval.sendTransactionAsync(
- testValidator.address,
- approval,
- {
- from: signerAddress,
- },
- ),
- );
- expect(res.logs.length).to.equal(1);
- const log = res.logs[0] as LogWithDecodedArgs<TestSignatureValidatorSignatureValidatorApprovalEventArgs>;
- const logArgs = log.args;
- expect(logArgs.signerAddress).to.equal(signerAddress);
- expect(logArgs.validatorAddress).to.equal(testValidator.address);
- expect(logArgs.approved).to.equal(approval);
- });
- });
-});
-// tslint:disable:max-file-line-count
-// tslint:enable:no-unnecessary-type-assertion
diff --git a/packages/contracts/test/exchange/transactions.ts b/packages/contracts/test/exchange/transactions.ts
deleted file mode 100644
index 1b5eef295..000000000
--- a/packages/contracts/test/exchange/transactions.ts
+++ /dev/null
@@ -1,462 +0,0 @@
-import { BlockchainLifecycle } from '@0x/dev-utils';
-import { assetDataUtils, generatePseudoRandomSalt } from '@0x/order-utils';
-import { OrderWithoutExchangeAddress, RevertReason, SignedOrder } from '@0x/types';
-import { BigNumber } from '@0x/utils';
-import * as chai from 'chai';
-import * as _ from 'lodash';
-
-import { DummyERC20TokenContract } from '../../generated-wrappers/dummy_erc20_token';
-import { ERC20ProxyContract } from '../../generated-wrappers/erc20_proxy';
-import { ExchangeContract } from '../../generated-wrappers/exchange';
-import { ExchangeWrapperContract } from '../../generated-wrappers/exchange_wrapper';
-import { WhitelistContract } from '../../generated-wrappers/whitelist';
-import { artifacts } from '../../src/artifacts';
-import { expectTransactionFailedAsync } from '../utils/assertions';
-import { chaiSetup } from '../utils/chai_setup';
-import { constants } from '../utils/constants';
-import { ERC20Wrapper } from '../utils/erc20_wrapper';
-import { ExchangeWrapper } from '../utils/exchange_wrapper';
-import { OrderFactory } from '../utils/order_factory';
-import { orderUtils } from '../utils/order_utils';
-import { TransactionFactory } from '../utils/transaction_factory';
-import { ERC20BalancesByOwner, SignedTransaction } from '../utils/types';
-import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper';
-
-chaiSetup.configure();
-const expect = chai.expect;
-const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
-
-describe('Exchange transactions', () => {
- let senderAddress: string;
- let owner: string;
- let makerAddress: string;
- let takerAddress: string;
- let feeRecipientAddress: string;
-
- let erc20TokenA: DummyERC20TokenContract;
- let erc20TokenB: DummyERC20TokenContract;
- let zrxToken: DummyERC20TokenContract;
- let exchange: ExchangeContract;
- let erc20Proxy: ERC20ProxyContract;
-
- let erc20Balances: ERC20BalancesByOwner;
- let signedOrder: SignedOrder;
- let signedTx: SignedTransaction;
- let orderWithoutExchangeAddress: OrderWithoutExchangeAddress;
- let orderFactory: OrderFactory;
- let makerTransactionFactory: TransactionFactory;
- let takerTransactionFactory: TransactionFactory;
- let exchangeWrapper: ExchangeWrapper;
- let erc20Wrapper: ERC20Wrapper;
-
- let defaultMakerTokenAddress: string;
- let defaultTakerTokenAddress: string;
- let makerPrivateKey: Buffer;
- let takerPrivateKey: Buffer;
-
- before(async () => {
- await blockchainLifecycle.startAsync();
- });
- after(async () => {
- await blockchainLifecycle.revertAsync();
- });
- beforeEach(async () => {
- await blockchainLifecycle.startAsync();
- });
- afterEach(async () => {
- await blockchainLifecycle.revertAsync();
- });
- before(async () => {
- const accounts = await web3Wrapper.getAvailableAddressesAsync();
- const usedAddresses = ([owner, senderAddress, makerAddress, takerAddress, feeRecipientAddress] = _.slice(
- accounts,
- 0,
- 5,
- ));
-
- erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner);
-
- const numDummyErc20ToDeploy = 3;
- [erc20TokenA, erc20TokenB, zrxToken] = await erc20Wrapper.deployDummyTokensAsync(
- numDummyErc20ToDeploy,
- constants.DUMMY_TOKEN_DECIMALS,
- );
- erc20Proxy = await erc20Wrapper.deployProxyAsync();
- await erc20Wrapper.setBalancesAndAllowancesAsync();
-
- exchange = await ExchangeContract.deployFrom0xArtifactAsync(
- artifacts.Exchange,
- provider,
- txDefaults,
- assetDataUtils.encodeERC20AssetData(zrxToken.address),
- );
- exchangeWrapper = new ExchangeWrapper(exchange, provider);
- await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner);
-
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc20Proxy.addAuthorizedAddress.sendTransactionAsync(exchange.address, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
-
- defaultMakerTokenAddress = erc20TokenA.address;
- defaultTakerTokenAddress = erc20TokenB.address;
-
- const defaultOrderParams = {
- ...constants.STATIC_ORDER_PARAMS,
- senderAddress,
- exchangeAddress: exchange.address,
- makerAddress,
- feeRecipientAddress,
- makerAssetData: assetDataUtils.encodeERC20AssetData(defaultMakerTokenAddress),
- takerAssetData: assetDataUtils.encodeERC20AssetData(defaultTakerTokenAddress),
- };
- makerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddress)];
- takerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(takerAddress)];
- orderFactory = new OrderFactory(makerPrivateKey, defaultOrderParams);
- makerTransactionFactory = new TransactionFactory(makerPrivateKey, exchange.address);
- takerTransactionFactory = new TransactionFactory(takerPrivateKey, exchange.address);
- });
- describe('executeTransaction', () => {
- describe('fillOrder', () => {
- let takerAssetFillAmount: BigNumber;
- beforeEach(async () => {
- erc20Balances = await erc20Wrapper.getBalancesAsync();
- signedOrder = await orderFactory.newSignedOrderAsync();
- orderWithoutExchangeAddress = orderUtils.getOrderWithoutExchangeAddress(signedOrder);
-
- takerAssetFillAmount = signedOrder.takerAssetAmount.div(2);
- const data = exchange.fillOrder.getABIEncodedTransactionData(
- orderWithoutExchangeAddress,
- takerAssetFillAmount,
- signedOrder.signature,
- );
- signedTx = takerTransactionFactory.newSignedTransaction(data);
- });
-
- it('should throw if not called by specified sender', async () => {
- return expectTransactionFailedAsync(
- exchangeWrapper.executeTransactionAsync(signedTx, takerAddress),
- RevertReason.FailedExecution,
- );
- });
-
- it('should transfer the correct amounts when signed by taker and called by sender', async () => {
- await exchangeWrapper.executeTransactionAsync(signedTx, senderAddress);
- const newBalances = await erc20Wrapper.getBalancesAsync();
- const makerAssetFillAmount = takerAssetFillAmount
- .times(signedOrder.makerAssetAmount)
- .dividedToIntegerBy(signedOrder.takerAssetAmount);
- const makerFeePaid = signedOrder.makerFee
- .times(makerAssetFillAmount)
- .dividedToIntegerBy(signedOrder.makerAssetAmount);
- const takerFeePaid = signedOrder.takerFee
- .times(makerAssetFillAmount)
- .dividedToIntegerBy(signedOrder.makerAssetAmount);
- expect(newBalances[makerAddress][defaultMakerTokenAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultMakerTokenAddress].minus(makerAssetFillAmount),
- );
- expect(newBalances[makerAddress][defaultTakerTokenAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultTakerTokenAddress].add(takerAssetFillAmount),
- );
- expect(newBalances[makerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][zrxToken.address].minus(makerFeePaid),
- );
- expect(newBalances[takerAddress][defaultTakerTokenAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultTakerTokenAddress].minus(takerAssetFillAmount),
- );
- expect(newBalances[takerAddress][defaultMakerTokenAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultMakerTokenAddress].add(makerAssetFillAmount),
- );
- expect(newBalances[takerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[takerAddress][zrxToken.address].minus(takerFeePaid),
- );
- expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[feeRecipientAddress][zrxToken.address].add(makerFeePaid.add(takerFeePaid)),
- );
- });
-
- it('should throw if the a 0x transaction with the same transactionHash has already been executed', async () => {
- await exchangeWrapper.executeTransactionAsync(signedTx, senderAddress);
- return expectTransactionFailedAsync(
- exchangeWrapper.executeTransactionAsync(signedTx, senderAddress),
- RevertReason.InvalidTxHash,
- );
- });
-
- it('should reset the currentContextAddress', async () => {
- await exchangeWrapper.executeTransactionAsync(signedTx, senderAddress);
- const currentContextAddress = await exchange.currentContextAddress.callAsync();
- expect(currentContextAddress).to.equal(constants.NULL_ADDRESS);
- });
- });
-
- describe('cancelOrder', () => {
- beforeEach(async () => {
- const data = exchange.cancelOrder.getABIEncodedTransactionData(orderWithoutExchangeAddress);
- signedTx = makerTransactionFactory.newSignedTransaction(data);
- });
-
- it('should throw if not called by specified sender', async () => {
- return expectTransactionFailedAsync(
- exchangeWrapper.executeTransactionAsync(signedTx, makerAddress),
- RevertReason.FailedExecution,
- );
- });
-
- it('should cancel the order when signed by maker and called by sender', async () => {
- await exchangeWrapper.executeTransactionAsync(signedTx, senderAddress);
- return expectTransactionFailedAsync(
- exchangeWrapper.fillOrderAsync(signedOrder, senderAddress),
- RevertReason.OrderUnfillable,
- );
- });
- });
-
- describe('cancelOrdersUpTo', () => {
- let exchangeWrapperContract: ExchangeWrapperContract;
-
- before(async () => {
- exchangeWrapperContract = await ExchangeWrapperContract.deployFrom0xArtifactAsync(
- artifacts.ExchangeWrapper,
- provider,
- txDefaults,
- exchange.address,
- );
- });
-
- it("should cancel an order if called from the order's sender", async () => {
- const orderSalt = new BigNumber(0);
- signedOrder = await orderFactory.newSignedOrderAsync({
- senderAddress: exchangeWrapperContract.address,
- salt: orderSalt,
- });
- const targetOrderEpoch = orderSalt.add(1);
- const cancelData = exchange.cancelOrdersUpTo.getABIEncodedTransactionData(targetOrderEpoch);
- const signedCancelTx = makerTransactionFactory.newSignedTransaction(cancelData);
- await exchangeWrapperContract.cancelOrdersUpTo.sendTransactionAsync(
- targetOrderEpoch,
- signedCancelTx.salt,
- signedCancelTx.signature,
- {
- from: makerAddress,
- },
- );
-
- const takerAssetFillAmount = signedOrder.takerAssetAmount;
- orderWithoutExchangeAddress = orderUtils.getOrderWithoutExchangeAddress(signedOrder);
- const fillData = exchange.fillOrder.getABIEncodedTransactionData(
- orderWithoutExchangeAddress,
- takerAssetFillAmount,
- signedOrder.signature,
- );
- const signedFillTx = takerTransactionFactory.newSignedTransaction(fillData);
- return expectTransactionFailedAsync(
- exchangeWrapperContract.fillOrder.sendTransactionAsync(
- orderWithoutExchangeAddress,
- takerAssetFillAmount,
- signedFillTx.salt,
- signedOrder.signature,
- signedFillTx.signature,
- { from: takerAddress },
- ),
- RevertReason.FailedExecution,
- );
- });
-
- it("should not cancel an order if not called from the order's sender", async () => {
- const orderSalt = new BigNumber(0);
- signedOrder = await orderFactory.newSignedOrderAsync({
- senderAddress: exchangeWrapperContract.address,
- salt: orderSalt,
- });
- const targetOrderEpoch = orderSalt.add(1);
- await exchangeWrapper.cancelOrdersUpToAsync(targetOrderEpoch, makerAddress);
-
- erc20Balances = await erc20Wrapper.getBalancesAsync();
- const takerAssetFillAmount = signedOrder.takerAssetAmount;
- orderWithoutExchangeAddress = orderUtils.getOrderWithoutExchangeAddress(signedOrder);
- const data = exchange.fillOrder.getABIEncodedTransactionData(
- orderWithoutExchangeAddress,
- takerAssetFillAmount,
- signedOrder.signature,
- );
- signedTx = takerTransactionFactory.newSignedTransaction(data);
- await exchangeWrapperContract.fillOrder.sendTransactionAsync(
- orderWithoutExchangeAddress,
- takerAssetFillAmount,
- signedTx.salt,
- signedOrder.signature,
- signedTx.signature,
- { from: takerAddress },
- );
-
- const newBalances = await erc20Wrapper.getBalancesAsync();
- const makerAssetFillAmount = takerAssetFillAmount
- .times(signedOrder.makerAssetAmount)
- .dividedToIntegerBy(signedOrder.takerAssetAmount);
- const makerFeePaid = signedOrder.makerFee
- .times(makerAssetFillAmount)
- .dividedToIntegerBy(signedOrder.makerAssetAmount);
- const takerFeePaid = signedOrder.takerFee
- .times(makerAssetFillAmount)
- .dividedToIntegerBy(signedOrder.makerAssetAmount);
- expect(newBalances[makerAddress][defaultMakerTokenAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultMakerTokenAddress].minus(makerAssetFillAmount),
- );
- expect(newBalances[makerAddress][defaultTakerTokenAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultTakerTokenAddress].add(takerAssetFillAmount),
- );
- expect(newBalances[makerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][zrxToken.address].minus(makerFeePaid),
- );
- expect(newBalances[takerAddress][defaultTakerTokenAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultTakerTokenAddress].minus(takerAssetFillAmount),
- );
- expect(newBalances[takerAddress][defaultMakerTokenAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultMakerTokenAddress].add(makerAssetFillAmount),
- );
- expect(newBalances[takerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[takerAddress][zrxToken.address].minus(takerFeePaid),
- );
- expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[feeRecipientAddress][zrxToken.address].add(makerFeePaid.add(takerFeePaid)),
- );
- });
- });
- });
-
- describe('Whitelist', () => {
- let whitelist: WhitelistContract;
- let whitelistOrderFactory: OrderFactory;
-
- before(async () => {
- whitelist = await WhitelistContract.deployFrom0xArtifactAsync(
- artifacts.Whitelist,
- provider,
- txDefaults,
- exchange.address,
- );
- const isApproved = true;
- await web3Wrapper.awaitTransactionSuccessAsync(
- await exchange.setSignatureValidatorApproval.sendTransactionAsync(whitelist.address, isApproved, {
- from: takerAddress,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const defaultOrderParams = {
- ...constants.STATIC_ORDER_PARAMS,
- senderAddress: whitelist.address,
- exchangeAddress: exchange.address,
- makerAddress,
- feeRecipientAddress,
- makerAssetData: assetDataUtils.encodeERC20AssetData(defaultMakerTokenAddress),
- takerAssetData: assetDataUtils.encodeERC20AssetData(defaultTakerTokenAddress),
- };
- whitelistOrderFactory = new OrderFactory(makerPrivateKey, defaultOrderParams);
- });
-
- beforeEach(async () => {
- signedOrder = await whitelistOrderFactory.newSignedOrderAsync();
- erc20Balances = await erc20Wrapper.getBalancesAsync();
- });
-
- it('should revert if maker has not been whitelisted', async () => {
- const isApproved = true;
- await web3Wrapper.awaitTransactionSuccessAsync(
- await whitelist.updateWhitelistStatus.sendTransactionAsync(takerAddress, isApproved, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
-
- orderWithoutExchangeAddress = orderUtils.getOrderWithoutExchangeAddress(signedOrder);
- const takerAssetFillAmount = signedOrder.takerAssetAmount;
- const salt = generatePseudoRandomSalt();
- return expectTransactionFailedAsync(
- whitelist.fillOrderIfWhitelisted.sendTransactionAsync(
- orderWithoutExchangeAddress,
- takerAssetFillAmount,
- salt,
- signedOrder.signature,
- { from: takerAddress },
- ),
- RevertReason.MakerNotWhitelisted,
- );
- });
-
- it('should revert if taker has not been whitelisted', async () => {
- const isApproved = true;
- await web3Wrapper.awaitTransactionSuccessAsync(
- await whitelist.updateWhitelistStatus.sendTransactionAsync(makerAddress, isApproved, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
-
- orderWithoutExchangeAddress = orderUtils.getOrderWithoutExchangeAddress(signedOrder);
- const takerAssetFillAmount = signedOrder.takerAssetAmount;
- const salt = generatePseudoRandomSalt();
- return expectTransactionFailedAsync(
- whitelist.fillOrderIfWhitelisted.sendTransactionAsync(
- orderWithoutExchangeAddress,
- takerAssetFillAmount,
- salt,
- signedOrder.signature,
- { from: takerAddress },
- ),
- RevertReason.TakerNotWhitelisted,
- );
- });
-
- it('should fill the order if maker and taker have been whitelisted', async () => {
- const isApproved = true;
- await web3Wrapper.awaitTransactionSuccessAsync(
- await whitelist.updateWhitelistStatus.sendTransactionAsync(makerAddress, isApproved, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
-
- await web3Wrapper.awaitTransactionSuccessAsync(
- await whitelist.updateWhitelistStatus.sendTransactionAsync(takerAddress, isApproved, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
-
- orderWithoutExchangeAddress = orderUtils.getOrderWithoutExchangeAddress(signedOrder);
- const takerAssetFillAmount = signedOrder.takerAssetAmount;
- const salt = generatePseudoRandomSalt();
- await web3Wrapper.awaitTransactionSuccessAsync(
- await whitelist.fillOrderIfWhitelisted.sendTransactionAsync(
- orderWithoutExchangeAddress,
- takerAssetFillAmount,
- salt,
- signedOrder.signature,
- { from: takerAddress },
- ),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
-
- const newBalances = await erc20Wrapper.getBalancesAsync();
-
- const makerAssetFillAmount = signedOrder.makerAssetAmount;
- const makerFeePaid = signedOrder.makerFee;
- const takerFeePaid = signedOrder.takerFee;
-
- expect(newBalances[makerAddress][defaultMakerTokenAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultMakerTokenAddress].minus(makerAssetFillAmount),
- );
- expect(newBalances[makerAddress][defaultTakerTokenAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultTakerTokenAddress].add(takerAssetFillAmount),
- );
- expect(newBalances[makerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][zrxToken.address].minus(makerFeePaid),
- );
- expect(newBalances[takerAddress][defaultTakerTokenAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultTakerTokenAddress].minus(takerAssetFillAmount),
- );
- expect(newBalances[takerAddress][defaultMakerTokenAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultMakerTokenAddress].add(makerAssetFillAmount),
- );
- expect(newBalances[takerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[takerAddress][zrxToken.address].minus(takerFeePaid),
- );
- expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[feeRecipientAddress][zrxToken.address].add(makerFeePaid.add(takerFeePaid)),
- );
- });
- });
-});
diff --git a/packages/contracts/test/exchange/wrapper.ts b/packages/contracts/test/exchange/wrapper.ts
deleted file mode 100644
index 6b660aac5..000000000
--- a/packages/contracts/test/exchange/wrapper.ts
+++ /dev/null
@@ -1,1452 +0,0 @@
-import { BlockchainLifecycle } from '@0x/dev-utils';
-import { assetDataUtils, orderHashUtils } 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 { DummyERC20TokenContract } from '../../generated-wrappers/dummy_erc20_token';
-import { DummyERC721TokenContract } from '../../generated-wrappers/dummy_erc721_token';
-import { ERC20ProxyContract } from '../../generated-wrappers/erc20_proxy';
-import { ERC721ProxyContract } from '../../generated-wrappers/erc721_proxy';
-import { ExchangeContract } from '../../generated-wrappers/exchange';
-import { ReentrantERC20TokenContract } from '../../generated-wrappers/reentrant_erc20_token';
-import { artifacts } from '../../src/artifacts';
-import { expectTransactionFailedAsync } from '../utils/assertions';
-import { getLatestBlockTimestampAsync, increaseTimeAndMineBlockAsync } from '../utils/block_timestamp';
-import { chaiSetup } from '../utils/chai_setup';
-import { constants } from '../utils/constants';
-import { ERC20Wrapper } from '../utils/erc20_wrapper';
-import { ERC721Wrapper } from '../utils/erc721_wrapper';
-import { ExchangeWrapper } from '../utils/exchange_wrapper';
-import { OrderFactory } from '../utils/order_factory';
-import { ERC20BalancesByOwner, OrderStatus } from '../utils/types';
-import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper';
-
-chaiSetup.configure();
-const expect = chai.expect;
-const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
-
-describe('Exchange wrappers', () => {
- let makerAddress: string;
- let owner: string;
- let takerAddress: string;
- let feeRecipientAddress: string;
-
- let erc20TokenA: DummyERC20TokenContract;
- let erc20TokenB: DummyERC20TokenContract;
- let zrxToken: DummyERC20TokenContract;
- let erc721Token: DummyERC721TokenContract;
- let exchange: ExchangeContract;
- let erc20Proxy: ERC20ProxyContract;
- let erc721Proxy: ERC721ProxyContract;
- let reentrantErc20Token: ReentrantERC20TokenContract;
-
- let exchangeWrapper: ExchangeWrapper;
- let erc20Wrapper: ERC20Wrapper;
- let erc721Wrapper: ERC721Wrapper;
- let erc20Balances: ERC20BalancesByOwner;
- let orderFactory: OrderFactory;
-
- let erc721MakerAssetId: BigNumber;
- let erc721TakerAssetId: BigNumber;
-
- let defaultMakerAssetAddress: string;
- let defaultTakerAssetAddress: string;
-
- before(async () => {
- await blockchainLifecycle.startAsync();
- });
- after(async () => {
- await blockchainLifecycle.revertAsync();
- });
- before(async () => {
- const accounts = await web3Wrapper.getAvailableAddressesAsync();
- const usedAddresses = ([owner, makerAddress, takerAddress, feeRecipientAddress] = _.slice(accounts, 0, 4));
-
- erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner);
- erc721Wrapper = new ERC721Wrapper(provider, usedAddresses, owner);
-
- const numDummyErc20ToDeploy = 3;
- [erc20TokenA, erc20TokenB, zrxToken] = await erc20Wrapper.deployDummyTokensAsync(
- numDummyErc20ToDeploy,
- constants.DUMMY_TOKEN_DECIMALS,
- );
- erc20Proxy = await erc20Wrapper.deployProxyAsync();
- await erc20Wrapper.setBalancesAndAllowancesAsync();
-
- [erc721Token] = await erc721Wrapper.deployDummyTokensAsync();
- erc721Proxy = await erc721Wrapper.deployProxyAsync();
- await erc721Wrapper.setBalancesAndAllowancesAsync();
- const erc721Balances = await erc721Wrapper.getBalancesAsync();
- erc721MakerAssetId = erc721Balances[makerAddress][erc721Token.address][0];
- erc721TakerAssetId = erc721Balances[takerAddress][erc721Token.address][0];
-
- exchange = await ExchangeContract.deployFrom0xArtifactAsync(
- artifacts.Exchange,
- provider,
- txDefaults,
- assetDataUtils.encodeERC20AssetData(zrxToken.address),
- );
- exchangeWrapper = new ExchangeWrapper(exchange, provider);
- await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner);
- await exchangeWrapper.registerAssetProxyAsync(erc721Proxy.address, owner);
-
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc20Proxy.addAuthorizedAddress.sendTransactionAsync(exchange.address, {
- from: owner,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc721Proxy.addAuthorizedAddress.sendTransactionAsync(exchange.address, {
- from: owner,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
-
- reentrantErc20Token = await ReentrantERC20TokenContract.deployFrom0xArtifactAsync(
- artifacts.ReentrantERC20Token,
- provider,
- txDefaults,
- exchange.address,
- );
-
- defaultMakerAssetAddress = erc20TokenA.address;
- defaultTakerAssetAddress = erc20TokenB.address;
-
- const defaultOrderParams = {
- ...constants.STATIC_ORDER_PARAMS,
- exchangeAddress: exchange.address,
- makerAddress,
- feeRecipientAddress,
- makerAssetData: assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress),
- takerAssetData: assetDataUtils.encodeERC20AssetData(defaultTakerAssetAddress),
- };
- const privateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddress)];
- orderFactory = new OrderFactory(privateKey, defaultOrderParams);
- });
- beforeEach(async () => {
- await blockchainLifecycle.startAsync();
- erc20Balances = await erc20Wrapper.getBalancesAsync();
- });
- afterEach(async () => {
- await blockchainLifecycle.revertAsync();
- });
- describe('fillOrKillOrder', () => {
- const reentrancyTest = (functionNames: string[]) => {
- _.forEach(functionNames, async (functionName: string, functionId: number) => {
- const description = `should not allow fillOrKillOrder to reenter the Exchange contract via ${functionName}`;
- it(description, async () => {
- const signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetData: assetDataUtils.encodeERC20AssetData(reentrantErc20Token.address),
- });
- await web3Wrapper.awaitTransactionSuccessAsync(
- await reentrantErc20Token.setCurrentFunction.sendTransactionAsync(functionId),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await expectTransactionFailedAsync(
- exchangeWrapper.fillOrKillOrderAsync(signedOrder, takerAddress),
- RevertReason.TransferFailed,
- );
- });
- });
- };
- describe('fillOrKillOrder reentrancy tests', () => reentrancyTest(constants.FUNCTIONS_WITH_MUTEX));
-
- it('should transfer the correct amounts', async () => {
- const signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(200), 18),
- });
- const takerAssetFillAmount = signedOrder.takerAssetAmount.div(2);
- await exchangeWrapper.fillOrKillOrderAsync(signedOrder, takerAddress, {
- takerAssetFillAmount,
- });
-
- const newBalances = await erc20Wrapper.getBalancesAsync();
-
- const makerAssetFilledAmount = takerAssetFillAmount
- .times(signedOrder.makerAssetAmount)
- .dividedToIntegerBy(signedOrder.takerAssetAmount);
- const makerFee = signedOrder.makerFee
- .times(makerAssetFilledAmount)
- .dividedToIntegerBy(signedOrder.makerAssetAmount);
- const takerFee = signedOrder.takerFee
- .times(makerAssetFilledAmount)
- .dividedToIntegerBy(signedOrder.makerAssetAmount);
- expect(newBalances[makerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultMakerAssetAddress].minus(makerAssetFilledAmount),
- );
- expect(newBalances[makerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultTakerAssetAddress].add(takerAssetFillAmount),
- );
- expect(newBalances[makerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][zrxToken.address].minus(makerFee),
- );
- expect(newBalances[takerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultTakerAssetAddress].minus(takerAssetFillAmount),
- );
- expect(newBalances[takerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultMakerAssetAddress].add(makerAssetFilledAmount),
- );
- expect(newBalances[takerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[takerAddress][zrxToken.address].minus(takerFee),
- );
- expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[feeRecipientAddress][zrxToken.address].add(makerFee.add(takerFee)),
- );
- });
-
- it('should throw if a signedOrder is expired', async () => {
- const currentTimestamp = await getLatestBlockTimestampAsync();
- const signedOrder = await orderFactory.newSignedOrderAsync({
- expirationTimeSeconds: new BigNumber(currentTimestamp).sub(10),
- });
-
- return expectTransactionFailedAsync(
- exchangeWrapper.fillOrKillOrderAsync(signedOrder, takerAddress),
- RevertReason.OrderUnfillable,
- );
- });
-
- it('should throw if entire takerAssetFillAmount not filled', async () => {
- const signedOrder = await orderFactory.newSignedOrderAsync();
-
- await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, {
- takerAssetFillAmount: signedOrder.takerAssetAmount.div(2),
- });
-
- return expectTransactionFailedAsync(
- exchangeWrapper.fillOrKillOrderAsync(signedOrder, takerAddress),
- RevertReason.CompleteFillFailed,
- );
- });
- });
-
- describe('fillOrderNoThrow', () => {
- const reentrancyTest = (functionNames: string[]) => {
- _.forEach(functionNames, async (functionName: string, functionId: number) => {
- const description = `should not allow fillOrderNoThrow to reenter the Exchange contract via ${functionName}`;
- it(description, async () => {
- const signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetData: assetDataUtils.encodeERC20AssetData(reentrantErc20Token.address),
- });
- await web3Wrapper.awaitTransactionSuccessAsync(
- await reentrantErc20Token.setCurrentFunction.sendTransactionAsync(functionId),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await exchangeWrapper.fillOrderNoThrowAsync(signedOrder, takerAddress);
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(erc20Balances).to.deep.equal(newBalances);
- });
- });
- };
- describe('fillOrderNoThrow reentrancy tests', () => reentrancyTest(constants.FUNCTIONS_WITH_MUTEX));
-
- it('should transfer the correct amounts', async () => {
- const signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(200), 18),
- });
- const takerAssetFillAmount = signedOrder.takerAssetAmount.div(2);
-
- await exchangeWrapper.fillOrderNoThrowAsync(signedOrder, takerAddress, {
- 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: 250000,
- });
-
- const newBalances = await erc20Wrapper.getBalancesAsync();
- const makerAssetFilledAmount = takerAssetFillAmount
- .times(signedOrder.makerAssetAmount)
- .dividedToIntegerBy(signedOrder.takerAssetAmount);
- const makerFee = signedOrder.makerFee
- .times(makerAssetFilledAmount)
- .dividedToIntegerBy(signedOrder.makerAssetAmount);
- const takerFee = signedOrder.takerFee
- .times(makerAssetFilledAmount)
- .dividedToIntegerBy(signedOrder.makerAssetAmount);
-
- expect(newBalances[makerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultMakerAssetAddress].minus(makerAssetFilledAmount),
- );
- expect(newBalances[makerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultTakerAssetAddress].add(takerAssetFillAmount),
- );
- expect(newBalances[makerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][zrxToken.address].minus(makerFee),
- );
- expect(newBalances[takerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultTakerAssetAddress].minus(takerAssetFillAmount),
- );
- expect(newBalances[takerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultMakerAssetAddress].add(makerAssetFilledAmount),
- );
- expect(newBalances[takerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[takerAddress][zrxToken.address].minus(takerFee),
- );
- expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[feeRecipientAddress][zrxToken.address].add(makerFee.add(takerFee)),
- );
- });
-
- it('should not change erc20Balances if maker erc20Balances are too low to fill order', async () => {
- const signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100000), 18),
- });
-
- await exchangeWrapper.fillOrderNoThrowAsync(signedOrder, takerAddress);
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(newBalances).to.be.deep.equal(erc20Balances);
- });
-
- it('should not change erc20Balances if taker erc20Balances are too low to fill order', async () => {
- const signedOrder = await orderFactory.newSignedOrderAsync({
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100000), 18),
- });
-
- await exchangeWrapper.fillOrderNoThrowAsync(signedOrder, takerAddress);
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(newBalances).to.be.deep.equal(erc20Balances);
- });
-
- it('should not change erc20Balances if maker allowances are too low to fill order', async () => {
- const signedOrder = await orderFactory.newSignedOrderAsync();
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc20TokenA.approve.sendTransactionAsync(erc20Proxy.address, new BigNumber(0), {
- from: makerAddress,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await exchangeWrapper.fillOrderNoThrowAsync(signedOrder, takerAddress);
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc20TokenA.approve.sendTransactionAsync(erc20Proxy.address, constants.INITIAL_ERC20_ALLOWANCE, {
- from: makerAddress,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
-
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(newBalances).to.be.deep.equal(erc20Balances);
- });
-
- it('should not change erc20Balances if taker allowances are too low to fill order', async () => {
- const signedOrder = await orderFactory.newSignedOrderAsync();
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc20TokenB.approve.sendTransactionAsync(erc20Proxy.address, new BigNumber(0), {
- from: takerAddress,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await exchangeWrapper.fillOrderNoThrowAsync(signedOrder, takerAddress);
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc20TokenB.approve.sendTransactionAsync(erc20Proxy.address, constants.INITIAL_ERC20_ALLOWANCE, {
- from: takerAddress,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
-
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(newBalances).to.be.deep.equal(erc20Balances);
- });
-
- it('should not change erc20Balances if makerAssetAddress is ZRX, makerAssetAmount + makerFee > maker balance', async () => {
- const makerZRXBalance = new BigNumber(erc20Balances[makerAddress][zrxToken.address]);
- const signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetAmount: makerZRXBalance,
- makerFee: new BigNumber(1),
- makerAssetData: assetDataUtils.encodeERC20AssetData(zrxToken.address),
- });
- await exchangeWrapper.fillOrderNoThrowAsync(signedOrder, takerAddress);
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(newBalances).to.be.deep.equal(erc20Balances);
- });
-
- it('should not change erc20Balances if makerAssetAddress is ZRX, makerAssetAmount + makerFee > maker allowance', async () => {
- const makerZRXAllowance = await zrxToken.allowance.callAsync(makerAddress, erc20Proxy.address);
- const signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetAmount: new BigNumber(makerZRXAllowance),
- makerFee: new BigNumber(1),
- makerAssetData: assetDataUtils.encodeERC20AssetData(zrxToken.address),
- });
- await exchangeWrapper.fillOrderNoThrowAsync(signedOrder, takerAddress);
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(newBalances).to.be.deep.equal(erc20Balances);
- });
-
- it('should not change erc20Balances if takerAssetAddress is ZRX, takerAssetAmount + takerFee > taker balance', async () => {
- const takerZRXBalance = new BigNumber(erc20Balances[takerAddress][zrxToken.address]);
- const signedOrder = await orderFactory.newSignedOrderAsync({
- takerAssetAmount: takerZRXBalance,
- takerFee: new BigNumber(1),
- takerAssetData: assetDataUtils.encodeERC20AssetData(zrxToken.address),
- });
- await exchangeWrapper.fillOrderNoThrowAsync(signedOrder, takerAddress);
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(newBalances).to.be.deep.equal(erc20Balances);
- });
-
- it('should not change erc20Balances if takerAssetAddress is ZRX, takerAssetAmount + takerFee > taker allowance', async () => {
- const takerZRXAllowance = await zrxToken.allowance.callAsync(takerAddress, erc20Proxy.address);
- const signedOrder = await orderFactory.newSignedOrderAsync({
- takerAssetAmount: new BigNumber(takerZRXAllowance),
- takerFee: new BigNumber(1),
- takerAssetData: assetDataUtils.encodeERC20AssetData(zrxToken.address),
- });
- await exchangeWrapper.fillOrderNoThrowAsync(signedOrder, takerAddress);
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(newBalances).to.be.deep.equal(erc20Balances);
- });
-
- it('should successfully exchange ERC721 tokens', async () => {
- // Construct Exchange parameters
- const makerAssetId = erc721MakerAssetId;
- const takerAssetId = erc721TakerAssetId;
- const signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetAmount: new BigNumber(1),
- takerAssetAmount: new BigNumber(1),
- makerAssetData: assetDataUtils.encodeERC721AssetData(erc721Token.address, makerAssetId),
- takerAssetData: assetDataUtils.encodeERC721AssetData(erc721Token.address, takerAssetId),
- });
- // Verify pre-conditions
- const initialOwnerMakerAsset = await erc721Token.ownerOf.callAsync(makerAssetId);
- expect(initialOwnerMakerAsset).to.be.bignumber.equal(makerAddress);
- const initialOwnerTakerAsset = await erc721Token.ownerOf.callAsync(takerAssetId);
- expect(initialOwnerTakerAsset).to.be.bignumber.equal(takerAddress);
- // Call Exchange
- const takerAssetFillAmount = signedOrder.takerAssetAmount;
- await exchangeWrapper.fillOrderNoThrowAsync(signedOrder, takerAddress, {
- 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: 280000,
- });
- // Verify post-conditions
- const newOwnerMakerAsset = await erc721Token.ownerOf.callAsync(makerAssetId);
- expect(newOwnerMakerAsset).to.be.bignumber.equal(takerAddress);
- const newOwnerTakerAsset = await erc721Token.ownerOf.callAsync(takerAssetId);
- expect(newOwnerTakerAsset).to.be.bignumber.equal(makerAddress);
- });
- });
-
- describe('batch functions', () => {
- let signedOrders: SignedOrder[];
- beforeEach(async () => {
- signedOrders = [
- await orderFactory.newSignedOrderAsync(),
- await orderFactory.newSignedOrderAsync(),
- await orderFactory.newSignedOrderAsync(),
- ];
- });
-
- describe('batchFillOrders', () => {
- const reentrancyTest = (functionNames: string[]) => {
- _.forEach(functionNames, async (functionName: string, functionId: number) => {
- const description = `should not allow batchFillOrders to reenter the Exchange contract via ${functionName}`;
- it(description, async () => {
- const signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetData: assetDataUtils.encodeERC20AssetData(reentrantErc20Token.address),
- });
- await web3Wrapper.awaitTransactionSuccessAsync(
- await reentrantErc20Token.setCurrentFunction.sendTransactionAsync(functionId),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await expectTransactionFailedAsync(
- exchangeWrapper.batchFillOrdersAsync([signedOrder], takerAddress),
- RevertReason.TransferFailed,
- );
- });
- });
- };
- describe('batchFillOrders reentrancy tests', () => reentrancyTest(constants.FUNCTIONS_WITH_MUTEX));
-
- it('should transfer the correct amounts', async () => {
- const takerAssetFillAmounts: BigNumber[] = [];
- const makerAssetAddress = erc20TokenA.address;
- const takerAssetAddress = erc20TokenB.address;
- _.forEach(signedOrders, signedOrder => {
- const takerAssetFillAmount = signedOrder.takerAssetAmount.div(2);
- const makerAssetFilledAmount = takerAssetFillAmount
- .times(signedOrder.makerAssetAmount)
- .dividedToIntegerBy(signedOrder.takerAssetAmount);
- const makerFee = signedOrder.makerFee
- .times(makerAssetFilledAmount)
- .dividedToIntegerBy(signedOrder.makerAssetAmount);
- const takerFee = signedOrder.takerFee
- .times(makerAssetFilledAmount)
- .dividedToIntegerBy(signedOrder.makerAssetAmount);
- takerAssetFillAmounts.push(takerAssetFillAmount);
- erc20Balances[makerAddress][makerAssetAddress] = erc20Balances[makerAddress][
- makerAssetAddress
- ].minus(makerAssetFilledAmount);
- erc20Balances[makerAddress][takerAssetAddress] = erc20Balances[makerAddress][takerAssetAddress].add(
- takerAssetFillAmount,
- );
- erc20Balances[makerAddress][zrxToken.address] = erc20Balances[makerAddress][zrxToken.address].minus(
- makerFee,
- );
- erc20Balances[takerAddress][makerAssetAddress] = erc20Balances[takerAddress][makerAssetAddress].add(
- makerAssetFilledAmount,
- );
- erc20Balances[takerAddress][takerAssetAddress] = erc20Balances[takerAddress][
- takerAssetAddress
- ].minus(takerAssetFillAmount);
- erc20Balances[takerAddress][zrxToken.address] = erc20Balances[takerAddress][zrxToken.address].minus(
- takerFee,
- );
- erc20Balances[feeRecipientAddress][zrxToken.address] = erc20Balances[feeRecipientAddress][
- zrxToken.address
- ].add(makerFee.add(takerFee));
- });
-
- await exchangeWrapper.batchFillOrdersAsync(signedOrders, takerAddress, {
- takerAssetFillAmounts,
- });
-
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(newBalances).to.be.deep.equal(erc20Balances);
- });
- });
-
- describe('batchFillOrKillOrders', () => {
- const reentrancyTest = (functionNames: string[]) => {
- _.forEach(functionNames, async (functionName: string, functionId: number) => {
- const description = `should not allow batchFillOrKillOrders to reenter the Exchange contract via ${functionName}`;
- it(description, async () => {
- const signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetData: assetDataUtils.encodeERC20AssetData(reentrantErc20Token.address),
- });
- await web3Wrapper.awaitTransactionSuccessAsync(
- await reentrantErc20Token.setCurrentFunction.sendTransactionAsync(functionId),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await expectTransactionFailedAsync(
- exchangeWrapper.batchFillOrKillOrdersAsync([signedOrder], takerAddress),
- RevertReason.TransferFailed,
- );
- });
- });
- };
- describe('batchFillOrKillOrders reentrancy tests', () => reentrancyTest(constants.FUNCTIONS_WITH_MUTEX));
-
- it('should transfer the correct amounts', async () => {
- const takerAssetFillAmounts: BigNumber[] = [];
- const makerAssetAddress = erc20TokenA.address;
- const takerAssetAddress = erc20TokenB.address;
- _.forEach(signedOrders, signedOrder => {
- const takerAssetFillAmount = signedOrder.takerAssetAmount.div(2);
- const makerAssetFilledAmount = takerAssetFillAmount
- .times(signedOrder.makerAssetAmount)
- .dividedToIntegerBy(signedOrder.takerAssetAmount);
- const makerFee = signedOrder.makerFee
- .times(makerAssetFilledAmount)
- .dividedToIntegerBy(signedOrder.makerAssetAmount);
- const takerFee = signedOrder.takerFee
- .times(makerAssetFilledAmount)
- .dividedToIntegerBy(signedOrder.makerAssetAmount);
- takerAssetFillAmounts.push(takerAssetFillAmount);
- erc20Balances[makerAddress][makerAssetAddress] = erc20Balances[makerAddress][
- makerAssetAddress
- ].minus(makerAssetFilledAmount);
- erc20Balances[makerAddress][takerAssetAddress] = erc20Balances[makerAddress][takerAssetAddress].add(
- takerAssetFillAmount,
- );
- erc20Balances[makerAddress][zrxToken.address] = erc20Balances[makerAddress][zrxToken.address].minus(
- makerFee,
- );
- erc20Balances[takerAddress][makerAssetAddress] = erc20Balances[takerAddress][makerAssetAddress].add(
- makerAssetFilledAmount,
- );
- erc20Balances[takerAddress][takerAssetAddress] = erc20Balances[takerAddress][
- takerAssetAddress
- ].minus(takerAssetFillAmount);
- erc20Balances[takerAddress][zrxToken.address] = erc20Balances[takerAddress][zrxToken.address].minus(
- takerFee,
- );
- erc20Balances[feeRecipientAddress][zrxToken.address] = erc20Balances[feeRecipientAddress][
- zrxToken.address
- ].add(makerFee.add(takerFee));
- });
-
- await exchangeWrapper.batchFillOrKillOrdersAsync(signedOrders, takerAddress, {
- takerAssetFillAmounts,
- });
-
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(newBalances).to.be.deep.equal(erc20Balances);
- });
-
- it('should throw if a single signedOrder does not fill the expected amount', async () => {
- const takerAssetFillAmounts: BigNumber[] = [];
- _.forEach(signedOrders, signedOrder => {
- const takerAssetFillAmount = signedOrder.takerAssetAmount.div(2);
- takerAssetFillAmounts.push(takerAssetFillAmount);
- });
-
- await exchangeWrapper.fillOrKillOrderAsync(signedOrders[0], takerAddress);
-
- return expectTransactionFailedAsync(
- exchangeWrapper.batchFillOrKillOrdersAsync(signedOrders, takerAddress, {
- takerAssetFillAmounts,
- }),
- RevertReason.OrderUnfillable,
- );
- });
- });
-
- describe('batchFillOrdersNoThrow', async () => {
- const reentrancyTest = (functionNames: string[]) => {
- _.forEach(functionNames, async (functionName: string, functionId: number) => {
- const description = `should not allow batchFillOrdersNoThrow to reenter the Exchange contract via ${functionName}`;
- it(description, async () => {
- const signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetData: assetDataUtils.encodeERC20AssetData(reentrantErc20Token.address),
- });
- await web3Wrapper.awaitTransactionSuccessAsync(
- await reentrantErc20Token.setCurrentFunction.sendTransactionAsync(functionId),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await exchangeWrapper.batchFillOrdersNoThrowAsync([signedOrder], takerAddress);
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(erc20Balances).to.deep.equal(newBalances);
- });
- });
- };
- describe('batchFillOrdersNoThrow reentrancy tests', () => reentrancyTest(constants.FUNCTIONS_WITH_MUTEX));
-
- it('should transfer the correct amounts', async () => {
- const takerAssetFillAmounts: BigNumber[] = [];
- const makerAssetAddress = erc20TokenA.address;
- const takerAssetAddress = erc20TokenB.address;
- _.forEach(signedOrders, signedOrder => {
- const takerAssetFillAmount = signedOrder.takerAssetAmount.div(2);
- const makerAssetFilledAmount = takerAssetFillAmount
- .times(signedOrder.makerAssetAmount)
- .dividedToIntegerBy(signedOrder.takerAssetAmount);
- const makerFee = signedOrder.makerFee
- .times(makerAssetFilledAmount)
- .dividedToIntegerBy(signedOrder.makerAssetAmount);
- const takerFee = signedOrder.takerFee
- .times(makerAssetFilledAmount)
- .dividedToIntegerBy(signedOrder.makerAssetAmount);
- takerAssetFillAmounts.push(takerAssetFillAmount);
- erc20Balances[makerAddress][makerAssetAddress] = erc20Balances[makerAddress][
- makerAssetAddress
- ].minus(makerAssetFilledAmount);
- erc20Balances[makerAddress][takerAssetAddress] = erc20Balances[makerAddress][takerAssetAddress].add(
- takerAssetFillAmount,
- );
- erc20Balances[makerAddress][zrxToken.address] = erc20Balances[makerAddress][zrxToken.address].minus(
- makerFee,
- );
- erc20Balances[takerAddress][makerAssetAddress] = erc20Balances[takerAddress][makerAssetAddress].add(
- makerAssetFilledAmount,
- );
- erc20Balances[takerAddress][takerAssetAddress] = erc20Balances[takerAddress][
- takerAssetAddress
- ].minus(takerAssetFillAmount);
- erc20Balances[takerAddress][zrxToken.address] = erc20Balances[takerAddress][zrxToken.address].minus(
- takerFee,
- );
- erc20Balances[feeRecipientAddress][zrxToken.address] = erc20Balances[feeRecipientAddress][
- zrxToken.address
- ].add(makerFee.add(takerFee));
- });
-
- await exchangeWrapper.batchFillOrdersNoThrowAsync(signedOrders, takerAddress, {
- 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,
- });
-
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(newBalances).to.be.deep.equal(erc20Balances);
- });
-
- it('should not throw if an order is invalid and fill the remaining orders', async () => {
- const takerAssetFillAmounts: BigNumber[] = [];
- const makerAssetAddress = erc20TokenA.address;
- const takerAssetAddress = erc20TokenB.address;
-
- const invalidOrder = {
- ...signedOrders[0],
- signature: '0x00',
- };
- const validOrders = signedOrders.slice(1);
-
- takerAssetFillAmounts.push(invalidOrder.takerAssetAmount.div(2));
- _.forEach(validOrders, signedOrder => {
- const takerAssetFillAmount = signedOrder.takerAssetAmount.div(2);
- const makerAssetFilledAmount = takerAssetFillAmount
- .times(signedOrder.makerAssetAmount)
- .dividedToIntegerBy(signedOrder.takerAssetAmount);
- const makerFee = signedOrder.makerFee
- .times(makerAssetFilledAmount)
- .dividedToIntegerBy(signedOrder.makerAssetAmount);
- const takerFee = signedOrder.takerFee
- .times(makerAssetFilledAmount)
- .dividedToIntegerBy(signedOrder.makerAssetAmount);
- takerAssetFillAmounts.push(takerAssetFillAmount);
- erc20Balances[makerAddress][makerAssetAddress] = erc20Balances[makerAddress][
- makerAssetAddress
- ].minus(makerAssetFilledAmount);
- erc20Balances[makerAddress][takerAssetAddress] = erc20Balances[makerAddress][takerAssetAddress].add(
- takerAssetFillAmount,
- );
- erc20Balances[makerAddress][zrxToken.address] = erc20Balances[makerAddress][zrxToken.address].minus(
- makerFee,
- );
- erc20Balances[takerAddress][makerAssetAddress] = erc20Balances[takerAddress][makerAssetAddress].add(
- makerAssetFilledAmount,
- );
- erc20Balances[takerAddress][takerAssetAddress] = erc20Balances[takerAddress][
- takerAssetAddress
- ].minus(takerAssetFillAmount);
- erc20Balances[takerAddress][zrxToken.address] = erc20Balances[takerAddress][zrxToken.address].minus(
- takerFee,
- );
- erc20Balances[feeRecipientAddress][zrxToken.address] = erc20Balances[feeRecipientAddress][
- zrxToken.address
- ].add(makerFee.add(takerFee));
- });
-
- const newOrders = [invalidOrder, ...validOrders];
- await exchangeWrapper.batchFillOrdersNoThrowAsync(newOrders, takerAddress, {
- 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: 450000,
- });
-
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(newBalances).to.be.deep.equal(erc20Balances);
- });
- });
-
- describe('marketSellOrders', () => {
- const reentrancyTest = (functionNames: string[]) => {
- _.forEach(functionNames, async (functionName: string, functionId: number) => {
- const description = `should not allow marketSellOrders to reenter the Exchange contract via ${functionName}`;
- it(description, async () => {
- const signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetData: assetDataUtils.encodeERC20AssetData(reentrantErc20Token.address),
- });
- await web3Wrapper.awaitTransactionSuccessAsync(
- await reentrantErc20Token.setCurrentFunction.sendTransactionAsync(functionId),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await expectTransactionFailedAsync(
- exchangeWrapper.marketSellOrdersAsync([signedOrder], takerAddress, {
- takerAssetFillAmount: signedOrder.takerAssetAmount,
- }),
- RevertReason.TransferFailed,
- );
- });
- });
- };
- describe('marketSellOrders reentrancy tests', () => reentrancyTest(constants.FUNCTIONS_WITH_MUTEX));
-
- it('should stop when the entire takerAssetFillAmount is filled', async () => {
- const takerAssetFillAmount = signedOrders[0].takerAssetAmount.plus(
- signedOrders[1].takerAssetAmount.div(2),
- );
- await exchangeWrapper.marketSellOrdersAsync(signedOrders, takerAddress, {
- takerAssetFillAmount,
- });
-
- const newBalances = await erc20Wrapper.getBalancesAsync();
-
- const makerAssetFilledAmount = signedOrders[0].makerAssetAmount.add(
- signedOrders[1].makerAssetAmount.dividedToIntegerBy(2),
- );
- const makerFee = signedOrders[0].makerFee.add(signedOrders[1].makerFee.dividedToIntegerBy(2));
- const takerFee = signedOrders[0].takerFee.add(signedOrders[1].takerFee.dividedToIntegerBy(2));
- expect(newBalances[makerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultMakerAssetAddress].minus(makerAssetFilledAmount),
- );
- expect(newBalances[makerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultTakerAssetAddress].add(takerAssetFillAmount),
- );
- expect(newBalances[makerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][zrxToken.address].minus(makerFee),
- );
- expect(newBalances[takerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultTakerAssetAddress].minus(takerAssetFillAmount),
- );
- expect(newBalances[takerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultMakerAssetAddress].add(makerAssetFilledAmount),
- );
- expect(newBalances[takerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[takerAddress][zrxToken.address].minus(takerFee),
- );
- expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[feeRecipientAddress][zrxToken.address].add(makerFee.add(takerFee)),
- );
- });
-
- it('should fill all signedOrders if cannot fill entire takerAssetFillAmount', async () => {
- const takerAssetFillAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(100000), 18);
- _.forEach(signedOrders, signedOrder => {
- erc20Balances[makerAddress][defaultMakerAssetAddress] = erc20Balances[makerAddress][
- defaultMakerAssetAddress
- ].minus(signedOrder.makerAssetAmount);
- erc20Balances[makerAddress][defaultTakerAssetAddress] = erc20Balances[makerAddress][
- defaultTakerAssetAddress
- ].add(signedOrder.takerAssetAmount);
- erc20Balances[makerAddress][zrxToken.address] = erc20Balances[makerAddress][zrxToken.address].minus(
- signedOrder.makerFee,
- );
- erc20Balances[takerAddress][defaultMakerAssetAddress] = erc20Balances[takerAddress][
- defaultMakerAssetAddress
- ].add(signedOrder.makerAssetAmount);
- erc20Balances[takerAddress][defaultTakerAssetAddress] = erc20Balances[takerAddress][
- defaultTakerAssetAddress
- ].minus(signedOrder.takerAssetAmount);
- erc20Balances[takerAddress][zrxToken.address] = erc20Balances[takerAddress][zrxToken.address].minus(
- signedOrder.takerFee,
- );
- erc20Balances[feeRecipientAddress][zrxToken.address] = erc20Balances[feeRecipientAddress][
- zrxToken.address
- ].add(signedOrder.makerFee.add(signedOrder.takerFee));
- });
- await exchangeWrapper.marketSellOrdersAsync(signedOrders, takerAddress, {
- takerAssetFillAmount,
- });
-
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(newBalances).to.be.deep.equal(erc20Balances);
- });
-
- it('should throw when a signedOrder does not use the same takerAssetAddress', async () => {
- signedOrders = [
- await orderFactory.newSignedOrderAsync(),
- await orderFactory.newSignedOrderAsync({
- takerAssetData: assetDataUtils.encodeERC20AssetData(zrxToken.address),
- }),
- await orderFactory.newSignedOrderAsync(),
- ];
-
- return expectTransactionFailedAsync(
- exchangeWrapper.marketSellOrdersAsync(signedOrders, takerAddress, {
- takerAssetFillAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(1000), 18),
- }),
- // We simply use the takerAssetData from the first order for all orders.
- // If they are not the same, the contract throws when validating the order signature
- RevertReason.InvalidOrderSignature,
- );
- });
- });
-
- describe('marketSellOrdersNoThrow', () => {
- const reentrancyTest = (functionNames: string[]) => {
- _.forEach(functionNames, async (functionName: string, functionId: number) => {
- const description = `should not allow marketSellOrdersNoThrow to reenter the Exchange contract via ${functionName}`;
- it(description, async () => {
- const signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetData: assetDataUtils.encodeERC20AssetData(reentrantErc20Token.address),
- });
- await web3Wrapper.awaitTransactionSuccessAsync(
- await reentrantErc20Token.setCurrentFunction.sendTransactionAsync(functionId),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await exchangeWrapper.marketSellOrdersNoThrowAsync([signedOrder], takerAddress, {
- takerAssetFillAmount: signedOrder.takerAssetAmount,
- });
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(erc20Balances).to.deep.equal(newBalances);
- });
- });
- };
- describe('marketSellOrdersNoThrow reentrancy tests', () => reentrancyTest(constants.FUNCTIONS_WITH_MUTEX));
-
- it('should stop when the entire takerAssetFillAmount is filled', async () => {
- const takerAssetFillAmount = signedOrders[0].takerAssetAmount.plus(
- signedOrders[1].takerAssetAmount.div(2),
- );
- await exchangeWrapper.marketSellOrdersNoThrowAsync(signedOrders, takerAddress, {
- 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: 6000000,
- });
-
- const newBalances = await erc20Wrapper.getBalancesAsync();
-
- const makerAssetFilledAmount = signedOrders[0].makerAssetAmount.add(
- signedOrders[1].makerAssetAmount.dividedToIntegerBy(2),
- );
- const makerFee = signedOrders[0].makerFee.add(signedOrders[1].makerFee.dividedToIntegerBy(2));
- const takerFee = signedOrders[0].takerFee.add(signedOrders[1].takerFee.dividedToIntegerBy(2));
- expect(newBalances[makerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultMakerAssetAddress].minus(makerAssetFilledAmount),
- );
- expect(newBalances[makerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultTakerAssetAddress].add(takerAssetFillAmount),
- );
- expect(newBalances[makerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][zrxToken.address].minus(makerFee),
- );
- expect(newBalances[takerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultTakerAssetAddress].minus(takerAssetFillAmount),
- );
- expect(newBalances[takerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultMakerAssetAddress].add(makerAssetFilledAmount),
- );
- expect(newBalances[takerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[takerAddress][zrxToken.address].minus(takerFee),
- );
- expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[feeRecipientAddress][zrxToken.address].add(makerFee.add(takerFee)),
- );
- });
-
- it('should fill all signedOrders if cannot fill entire takerAssetFillAmount', async () => {
- const takerAssetFillAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(100000), 18);
- _.forEach(signedOrders, signedOrder => {
- erc20Balances[makerAddress][defaultMakerAssetAddress] = erc20Balances[makerAddress][
- defaultMakerAssetAddress
- ].minus(signedOrder.makerAssetAmount);
- erc20Balances[makerAddress][defaultTakerAssetAddress] = erc20Balances[makerAddress][
- defaultTakerAssetAddress
- ].add(signedOrder.takerAssetAmount);
- erc20Balances[makerAddress][zrxToken.address] = erc20Balances[makerAddress][zrxToken.address].minus(
- signedOrder.makerFee,
- );
- erc20Balances[takerAddress][defaultMakerAssetAddress] = erc20Balances[takerAddress][
- defaultMakerAssetAddress
- ].add(signedOrder.makerAssetAmount);
- erc20Balances[takerAddress][defaultTakerAssetAddress] = erc20Balances[takerAddress][
- defaultTakerAssetAddress
- ].minus(signedOrder.takerAssetAmount);
- erc20Balances[takerAddress][zrxToken.address] = erc20Balances[takerAddress][zrxToken.address].minus(
- signedOrder.takerFee,
- );
- erc20Balances[feeRecipientAddress][zrxToken.address] = erc20Balances[feeRecipientAddress][
- zrxToken.address
- ].add(signedOrder.makerFee.add(signedOrder.takerFee));
- });
- await exchangeWrapper.marketSellOrdersNoThrowAsync(signedOrders, takerAddress, {
- 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,
- });
-
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(newBalances).to.be.deep.equal(erc20Balances);
- });
-
- it('should not fill a signedOrder that does not use the same takerAssetAddress', async () => {
- signedOrders = [
- await orderFactory.newSignedOrderAsync(),
- await orderFactory.newSignedOrderAsync(),
- await orderFactory.newSignedOrderAsync({
- takerAssetData: assetDataUtils.encodeERC20AssetData(zrxToken.address),
- }),
- ];
- const takerAssetFillAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(100000), 18);
- const filledSignedOrders = signedOrders.slice(0, -1);
- _.forEach(filledSignedOrders, signedOrder => {
- erc20Balances[makerAddress][defaultMakerAssetAddress] = erc20Balances[makerAddress][
- defaultMakerAssetAddress
- ].minus(signedOrder.makerAssetAmount);
- erc20Balances[makerAddress][defaultTakerAssetAddress] = erc20Balances[makerAddress][
- defaultTakerAssetAddress
- ].add(signedOrder.takerAssetAmount);
- erc20Balances[makerAddress][zrxToken.address] = erc20Balances[makerAddress][zrxToken.address].minus(
- signedOrder.makerFee,
- );
- erc20Balances[takerAddress][defaultMakerAssetAddress] = erc20Balances[takerAddress][
- defaultMakerAssetAddress
- ].add(signedOrder.makerAssetAmount);
- erc20Balances[takerAddress][defaultTakerAssetAddress] = erc20Balances[takerAddress][
- defaultTakerAssetAddress
- ].minus(signedOrder.takerAssetAmount);
- erc20Balances[takerAddress][zrxToken.address] = erc20Balances[takerAddress][zrxToken.address].minus(
- signedOrder.takerFee,
- );
- erc20Balances[feeRecipientAddress][zrxToken.address] = erc20Balances[feeRecipientAddress][
- zrxToken.address
- ].add(signedOrder.makerFee.add(signedOrder.takerFee));
- });
- await exchangeWrapper.marketSellOrdersNoThrowAsync(signedOrders, takerAddress, {
- 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,
- });
-
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(newBalances).to.be.deep.equal(erc20Balances);
- });
- });
-
- describe('marketBuyOrders', () => {
- const reentrancyTest = (functionNames: string[]) => {
- _.forEach(functionNames, async (functionName: string, functionId: number) => {
- const description = `should not allow marketBuyOrders to reenter the Exchange contract via ${functionName}`;
- it(description, async () => {
- const signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetData: assetDataUtils.encodeERC20AssetData(reentrantErc20Token.address),
- });
- await web3Wrapper.awaitTransactionSuccessAsync(
- await reentrantErc20Token.setCurrentFunction.sendTransactionAsync(functionId),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await expectTransactionFailedAsync(
- exchangeWrapper.marketBuyOrdersAsync([signedOrder], takerAddress, {
- makerAssetFillAmount: signedOrder.makerAssetAmount,
- }),
- RevertReason.TransferFailed,
- );
- });
- });
- };
- describe('marketBuyOrders reentrancy tests', () => reentrancyTest(constants.FUNCTIONS_WITH_MUTEX));
-
- it('should stop when the entire makerAssetFillAmount is filled', async () => {
- const makerAssetFillAmount = signedOrders[0].makerAssetAmount.plus(
- signedOrders[1].makerAssetAmount.div(2),
- );
- await exchangeWrapper.marketBuyOrdersAsync(signedOrders, takerAddress, {
- makerAssetFillAmount,
- });
-
- const newBalances = await erc20Wrapper.getBalancesAsync();
-
- const makerAmountBought = signedOrders[0].takerAssetAmount.add(
- signedOrders[1].takerAssetAmount.dividedToIntegerBy(2),
- );
- const makerFee = signedOrders[0].makerFee.add(signedOrders[1].makerFee.dividedToIntegerBy(2));
- const takerFee = signedOrders[0].takerFee.add(signedOrders[1].takerFee.dividedToIntegerBy(2));
- expect(newBalances[makerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount),
- );
- expect(newBalances[makerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultTakerAssetAddress].add(makerAmountBought),
- );
- expect(newBalances[makerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][zrxToken.address].minus(makerFee),
- );
- expect(newBalances[takerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultTakerAssetAddress].minus(makerAmountBought),
- );
- expect(newBalances[takerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultMakerAssetAddress].add(makerAssetFillAmount),
- );
- expect(newBalances[takerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[takerAddress][zrxToken.address].minus(takerFee),
- );
- expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[feeRecipientAddress][zrxToken.address].add(makerFee.add(takerFee)),
- );
- });
-
- it('should fill all signedOrders if cannot fill entire makerAssetFillAmount', async () => {
- const makerAssetFillAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(100000), 18);
- _.forEach(signedOrders, signedOrder => {
- erc20Balances[makerAddress][defaultMakerAssetAddress] = erc20Balances[makerAddress][
- defaultMakerAssetAddress
- ].minus(signedOrder.makerAssetAmount);
- erc20Balances[makerAddress][defaultTakerAssetAddress] = erc20Balances[makerAddress][
- defaultTakerAssetAddress
- ].add(signedOrder.takerAssetAmount);
- erc20Balances[makerAddress][zrxToken.address] = erc20Balances[makerAddress][zrxToken.address].minus(
- signedOrder.makerFee,
- );
- erc20Balances[takerAddress][defaultMakerAssetAddress] = erc20Balances[takerAddress][
- defaultMakerAssetAddress
- ].add(signedOrder.makerAssetAmount);
- erc20Balances[takerAddress][defaultTakerAssetAddress] = erc20Balances[takerAddress][
- defaultTakerAssetAddress
- ].minus(signedOrder.takerAssetAmount);
- erc20Balances[takerAddress][zrxToken.address] = erc20Balances[takerAddress][zrxToken.address].minus(
- signedOrder.takerFee,
- );
- erc20Balances[feeRecipientAddress][zrxToken.address] = erc20Balances[feeRecipientAddress][
- zrxToken.address
- ].add(signedOrder.makerFee.add(signedOrder.takerFee));
- });
- await exchangeWrapper.marketBuyOrdersAsync(signedOrders, takerAddress, {
- makerAssetFillAmount,
- });
-
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(newBalances).to.be.deep.equal(erc20Balances);
- });
-
- it('should throw when a signedOrder does not use the same makerAssetAddress', async () => {
- signedOrders = [
- await orderFactory.newSignedOrderAsync(),
- await orderFactory.newSignedOrderAsync({
- makerAssetData: assetDataUtils.encodeERC20AssetData(zrxToken.address),
- }),
- await orderFactory.newSignedOrderAsync(),
- ];
-
- return expectTransactionFailedAsync(
- exchangeWrapper.marketBuyOrdersAsync(signedOrders, takerAddress, {
- makerAssetFillAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(1000), 18),
- }),
- RevertReason.InvalidOrderSignature,
- );
- });
- });
-
- describe('marketBuyOrdersNoThrow', () => {
- const reentrancyTest = (functionNames: string[]) => {
- _.forEach(functionNames, async (functionName: string, functionId: number) => {
- const description = `should not allow marketBuyOrdersNoThrow to reenter the Exchange contract via ${functionName}`;
- it(description, async () => {
- const signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetData: assetDataUtils.encodeERC20AssetData(reentrantErc20Token.address),
- });
- await web3Wrapper.awaitTransactionSuccessAsync(
- await reentrantErc20Token.setCurrentFunction.sendTransactionAsync(functionId),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await exchangeWrapper.marketBuyOrdersNoThrowAsync([signedOrder], takerAddress, {
- makerAssetFillAmount: signedOrder.makerAssetAmount,
- });
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(erc20Balances).to.deep.equal(newBalances);
- });
- });
- };
- describe('marketBuyOrdersNoThrow reentrancy tests', () => reentrancyTest(constants.FUNCTIONS_WITH_MUTEX));
-
- it('should stop when the entire makerAssetFillAmount is filled', async () => {
- const makerAssetFillAmount = signedOrders[0].makerAssetAmount.plus(
- signedOrders[1].makerAssetAmount.div(2),
- );
- await exchangeWrapper.marketBuyOrdersNoThrowAsync(signedOrders, takerAddress, {
- makerAssetFillAmount,
- // 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,
- });
-
- const newBalances = await erc20Wrapper.getBalancesAsync();
-
- const makerAmountBought = signedOrders[0].takerAssetAmount.add(
- signedOrders[1].takerAssetAmount.dividedToIntegerBy(2),
- );
- const makerFee = signedOrders[0].makerFee.add(signedOrders[1].makerFee.dividedToIntegerBy(2));
- const takerFee = signedOrders[0].takerFee.add(signedOrders[1].takerFee.dividedToIntegerBy(2));
- expect(newBalances[makerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount),
- );
- expect(newBalances[makerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultTakerAssetAddress].add(makerAmountBought),
- );
- expect(newBalances[makerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][zrxToken.address].minus(makerFee),
- );
- expect(newBalances[takerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultTakerAssetAddress].minus(makerAmountBought),
- );
- expect(newBalances[takerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultMakerAssetAddress].add(makerAssetFillAmount),
- );
- expect(newBalances[takerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[takerAddress][zrxToken.address].minus(takerFee),
- );
- expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[feeRecipientAddress][zrxToken.address].add(makerFee.add(takerFee)),
- );
- });
-
- it('should fill all signedOrders if cannot fill entire makerAssetFillAmount', async () => {
- const makerAssetFillAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(100000), 18);
- _.forEach(signedOrders, signedOrder => {
- erc20Balances[makerAddress][defaultMakerAssetAddress] = erc20Balances[makerAddress][
- defaultMakerAssetAddress
- ].minus(signedOrder.makerAssetAmount);
- erc20Balances[makerAddress][defaultTakerAssetAddress] = erc20Balances[makerAddress][
- defaultTakerAssetAddress
- ].add(signedOrder.takerAssetAmount);
- erc20Balances[makerAddress][zrxToken.address] = erc20Balances[makerAddress][zrxToken.address].minus(
- signedOrder.makerFee,
- );
- erc20Balances[takerAddress][defaultMakerAssetAddress] = erc20Balances[takerAddress][
- defaultMakerAssetAddress
- ].add(signedOrder.makerAssetAmount);
- erc20Balances[takerAddress][defaultTakerAssetAddress] = erc20Balances[takerAddress][
- defaultTakerAssetAddress
- ].minus(signedOrder.takerAssetAmount);
- erc20Balances[takerAddress][zrxToken.address] = erc20Balances[takerAddress][zrxToken.address].minus(
- signedOrder.takerFee,
- );
- erc20Balances[feeRecipientAddress][zrxToken.address] = erc20Balances[feeRecipientAddress][
- zrxToken.address
- ].add(signedOrder.makerFee.add(signedOrder.takerFee));
- });
- await exchangeWrapper.marketBuyOrdersNoThrowAsync(signedOrders, takerAddress, {
- makerAssetFillAmount,
- // 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,
- });
-
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(newBalances).to.be.deep.equal(erc20Balances);
- });
-
- it('should not fill a signedOrder that does not use the same makerAssetAddress', async () => {
- signedOrders = [
- await orderFactory.newSignedOrderAsync(),
- await orderFactory.newSignedOrderAsync(),
- await orderFactory.newSignedOrderAsync({
- makerAssetData: assetDataUtils.encodeERC20AssetData(zrxToken.address),
- }),
- ];
-
- const makerAssetFillAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(100000), 18);
- const filledSignedOrders = signedOrders.slice(0, -1);
- _.forEach(filledSignedOrders, signedOrder => {
- erc20Balances[makerAddress][defaultMakerAssetAddress] = erc20Balances[makerAddress][
- defaultMakerAssetAddress
- ].minus(signedOrder.makerAssetAmount);
- erc20Balances[makerAddress][defaultTakerAssetAddress] = erc20Balances[makerAddress][
- defaultTakerAssetAddress
- ].add(signedOrder.takerAssetAmount);
- erc20Balances[makerAddress][zrxToken.address] = erc20Balances[makerAddress][zrxToken.address].minus(
- signedOrder.makerFee,
- );
- erc20Balances[takerAddress][defaultMakerAssetAddress] = erc20Balances[takerAddress][
- defaultMakerAssetAddress
- ].add(signedOrder.makerAssetAmount);
- erc20Balances[takerAddress][defaultTakerAssetAddress] = erc20Balances[takerAddress][
- defaultTakerAssetAddress
- ].minus(signedOrder.takerAssetAmount);
- erc20Balances[takerAddress][zrxToken.address] = erc20Balances[takerAddress][zrxToken.address].minus(
- signedOrder.takerFee,
- );
- erc20Balances[feeRecipientAddress][zrxToken.address] = erc20Balances[feeRecipientAddress][
- zrxToken.address
- ].add(signedOrder.makerFee.add(signedOrder.takerFee));
- });
- await exchangeWrapper.marketBuyOrdersNoThrowAsync(signedOrders, takerAddress, {
- makerAssetFillAmount,
- // 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,
- });
-
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(newBalances).to.be.deep.equal(erc20Balances);
- });
- });
-
- describe('batchCancelOrders', () => {
- it('should be able to cancel multiple signedOrders', async () => {
- const takerAssetCancelAmounts = _.map(signedOrders, signedOrder => signedOrder.takerAssetAmount);
- await exchangeWrapper.batchCancelOrdersAsync(signedOrders, makerAddress);
-
- await exchangeWrapper.batchFillOrdersNoThrowAsync(signedOrders, takerAddress, {
- takerAssetFillAmounts: takerAssetCancelAmounts,
- });
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(erc20Balances).to.be.deep.equal(newBalances);
- });
- });
-
- describe('getOrdersInfo', () => {
- beforeEach(async () => {
- signedOrders = [
- await orderFactory.newSignedOrderAsync(),
- await orderFactory.newSignedOrderAsync(),
- await orderFactory.newSignedOrderAsync(),
- ];
- });
- it('should get the correct information for multiple unfilled orders', async () => {
- const ordersInfo = await exchangeWrapper.getOrdersInfoAsync(signedOrders);
- expect(ordersInfo.length).to.be.equal(3);
- _.forEach(signedOrders, (signedOrder, index) => {
- const expectedOrderHash = orderHashUtils.getOrderHashHex(signedOrder);
- const expectedTakerAssetFilledAmount = new BigNumber(0);
- const expectedOrderStatus = OrderStatus.FILLABLE;
- const orderInfo = ordersInfo[index];
- expect(orderInfo.orderHash).to.be.equal(expectedOrderHash);
- expect(orderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(expectedTakerAssetFilledAmount);
- expect(orderInfo.orderStatus).to.equal(expectedOrderStatus);
- });
- });
- it('should get the correct information for multiple partially filled orders', async () => {
- const takerAssetFillAmounts = _.map(signedOrders, signedOrder => signedOrder.takerAssetAmount.div(2));
- await exchangeWrapper.batchFillOrdersAsync(signedOrders, takerAddress, { takerAssetFillAmounts });
- const ordersInfo = await exchangeWrapper.getOrdersInfoAsync(signedOrders);
- expect(ordersInfo.length).to.be.equal(3);
- _.forEach(signedOrders, (signedOrder, index) => {
- const expectedOrderHash = orderHashUtils.getOrderHashHex(signedOrder);
- const expectedTakerAssetFilledAmount = signedOrder.takerAssetAmount.div(2);
- const expectedOrderStatus = OrderStatus.FILLABLE;
- const orderInfo = ordersInfo[index];
- expect(orderInfo.orderHash).to.be.equal(expectedOrderHash);
- expect(orderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(expectedTakerAssetFilledAmount);
- expect(orderInfo.orderStatus).to.equal(expectedOrderStatus);
- });
- });
- it('should get the correct information for multiple fully filled orders', async () => {
- await exchangeWrapper.batchFillOrdersAsync(signedOrders, takerAddress);
- const ordersInfo = await exchangeWrapper.getOrdersInfoAsync(signedOrders);
- expect(ordersInfo.length).to.be.equal(3);
- _.forEach(signedOrders, (signedOrder, index) => {
- const expectedOrderHash = orderHashUtils.getOrderHashHex(signedOrder);
- const expectedTakerAssetFilledAmount = signedOrder.takerAssetAmount;
- const expectedOrderStatus = OrderStatus.FULLY_FILLED;
- const orderInfo = ordersInfo[index];
- expect(orderInfo.orderHash).to.be.equal(expectedOrderHash);
- expect(orderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(expectedTakerAssetFilledAmount);
- expect(orderInfo.orderStatus).to.equal(expectedOrderStatus);
- });
- });
- it('should get the correct information for multiple cancelled and unfilled orders', async () => {
- await exchangeWrapper.batchCancelOrdersAsync(signedOrders, makerAddress);
- const ordersInfo = await exchangeWrapper.getOrdersInfoAsync(signedOrders);
- expect(ordersInfo.length).to.be.equal(3);
- _.forEach(signedOrders, (signedOrder, index) => {
- const expectedOrderHash = orderHashUtils.getOrderHashHex(signedOrder);
- const expectedTakerAssetFilledAmount = new BigNumber(0);
- const expectedOrderStatus = OrderStatus.CANCELLED;
- const orderInfo = ordersInfo[index];
- expect(orderInfo.orderHash).to.be.equal(expectedOrderHash);
- expect(orderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(expectedTakerAssetFilledAmount);
- expect(orderInfo.orderStatus).to.equal(expectedOrderStatus);
- });
- });
- it('should get the correct information for multiple cancelled and partially filled orders', async () => {
- const takerAssetFillAmounts = _.map(signedOrders, signedOrder => signedOrder.takerAssetAmount.div(2));
- await exchangeWrapper.batchFillOrdersAsync(signedOrders, takerAddress, { takerAssetFillAmounts });
- await exchangeWrapper.batchCancelOrdersAsync(signedOrders, makerAddress);
- const ordersInfo = await exchangeWrapper.getOrdersInfoAsync(signedOrders);
- expect(ordersInfo.length).to.be.equal(3);
- _.forEach(signedOrders, (signedOrder, index) => {
- const expectedOrderHash = orderHashUtils.getOrderHashHex(signedOrder);
- const expectedTakerAssetFilledAmount = signedOrder.takerAssetAmount.div(2);
- const expectedOrderStatus = OrderStatus.CANCELLED;
- const orderInfo = ordersInfo[index];
- expect(orderInfo.orderHash).to.be.equal(expectedOrderHash);
- expect(orderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(expectedTakerAssetFilledAmount);
- expect(orderInfo.orderStatus).to.equal(expectedOrderStatus);
- });
- });
- it('should get the correct information for multiple expired and unfilled orders', async () => {
- const currentTimestamp = await getLatestBlockTimestampAsync();
- const timeUntilExpiration = signedOrders[0].expirationTimeSeconds.minus(currentTimestamp).toNumber();
- await increaseTimeAndMineBlockAsync(timeUntilExpiration);
- const ordersInfo = await exchangeWrapper.getOrdersInfoAsync(signedOrders);
- expect(ordersInfo.length).to.be.equal(3);
- _.forEach(signedOrders, (signedOrder, index) => {
- const expectedOrderHash = orderHashUtils.getOrderHashHex(signedOrder);
- const expectedTakerAssetFilledAmount = new BigNumber(0);
- const expectedOrderStatus = OrderStatus.EXPIRED;
- const orderInfo = ordersInfo[index];
- expect(orderInfo.orderHash).to.be.equal(expectedOrderHash);
- expect(orderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(expectedTakerAssetFilledAmount);
- expect(orderInfo.orderStatus).to.equal(expectedOrderStatus);
- });
- });
- it('should get the correct information for multiple expired and partially filled orders', async () => {
- const takerAssetFillAmounts = _.map(signedOrders, signedOrder => signedOrder.takerAssetAmount.div(2));
- await exchangeWrapper.batchFillOrdersAsync(signedOrders, takerAddress, { takerAssetFillAmounts });
- const currentTimestamp = await getLatestBlockTimestampAsync();
- const timeUntilExpiration = signedOrders[0].expirationTimeSeconds.minus(currentTimestamp).toNumber();
- await increaseTimeAndMineBlockAsync(timeUntilExpiration);
- const ordersInfo = await exchangeWrapper.getOrdersInfoAsync(signedOrders);
- expect(ordersInfo.length).to.be.equal(3);
- _.forEach(signedOrders, (signedOrder, index) => {
- const expectedOrderHash = orderHashUtils.getOrderHashHex(signedOrder);
- const expectedTakerAssetFilledAmount = signedOrder.takerAssetAmount.div(2);
- const expectedOrderStatus = OrderStatus.EXPIRED;
- const orderInfo = ordersInfo[index];
- expect(orderInfo.orderHash).to.be.equal(expectedOrderHash);
- expect(orderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(expectedTakerAssetFilledAmount);
- expect(orderInfo.orderStatus).to.equal(expectedOrderStatus);
- });
- });
- it('should get the correct information for a mix of unfilled, partially filled, fully filled, cancelled, and expired orders', async () => {
- const unfilledOrder = await orderFactory.newSignedOrderAsync();
- const partiallyFilledOrder = await orderFactory.newSignedOrderAsync();
- await exchangeWrapper.fillOrderAsync(partiallyFilledOrder, takerAddress, {
- takerAssetFillAmount: partiallyFilledOrder.takerAssetAmount.div(2),
- });
- const fullyFilledOrder = await orderFactory.newSignedOrderAsync();
- await exchangeWrapper.fillOrderAsync(fullyFilledOrder, takerAddress);
- const cancelledOrder = await orderFactory.newSignedOrderAsync();
- await exchangeWrapper.cancelOrderAsync(cancelledOrder, makerAddress);
- const currentTimestamp = await getLatestBlockTimestampAsync();
- const expiredOrder = await orderFactory.newSignedOrderAsync({
- expirationTimeSeconds: new BigNumber(currentTimestamp),
- });
- signedOrders = [unfilledOrder, partiallyFilledOrder, fullyFilledOrder, cancelledOrder, expiredOrder];
- const ordersInfo = await exchangeWrapper.getOrdersInfoAsync(signedOrders);
- expect(ordersInfo.length).to.be.equal(5);
-
- const expectedUnfilledOrderHash = orderHashUtils.getOrderHashHex(unfilledOrder);
- const expectedUnfilledTakerAssetFilledAmount = new BigNumber(0);
- const expectedUnfilledOrderStatus = OrderStatus.FILLABLE;
- const unfilledOrderInfo = ordersInfo[0];
- expect(unfilledOrderInfo.orderHash).to.be.equal(expectedUnfilledOrderHash);
- expect(unfilledOrderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(
- expectedUnfilledTakerAssetFilledAmount,
- );
- expect(unfilledOrderInfo.orderStatus).to.be.equal(expectedUnfilledOrderStatus);
-
- const expectedPartialOrderHash = orderHashUtils.getOrderHashHex(partiallyFilledOrder);
- const expectedPartialTakerAssetFilledAmount = partiallyFilledOrder.takerAssetAmount.div(2);
- const expectedPartialOrderStatus = OrderStatus.FILLABLE;
- const partialOrderInfo = ordersInfo[1];
- expect(partialOrderInfo.orderHash).to.be.equal(expectedPartialOrderHash);
- expect(partialOrderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(
- expectedPartialTakerAssetFilledAmount,
- );
- expect(partialOrderInfo.orderStatus).to.be.equal(expectedPartialOrderStatus);
-
- const expectedFilledOrderHash = orderHashUtils.getOrderHashHex(fullyFilledOrder);
- const expectedFilledTakerAssetFilledAmount = fullyFilledOrder.takerAssetAmount;
- const expectedFilledOrderStatus = OrderStatus.FULLY_FILLED;
- const filledOrderInfo = ordersInfo[2];
- expect(filledOrderInfo.orderHash).to.be.equal(expectedFilledOrderHash);
- expect(filledOrderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(
- expectedFilledTakerAssetFilledAmount,
- );
- expect(filledOrderInfo.orderStatus).to.be.equal(expectedFilledOrderStatus);
-
- const expectedCancelledOrderHash = orderHashUtils.getOrderHashHex(cancelledOrder);
- const expectedCancelledTakerAssetFilledAmount = new BigNumber(0);
- const expectedCancelledOrderStatus = OrderStatus.CANCELLED;
- const cancelledOrderInfo = ordersInfo[3];
- expect(cancelledOrderInfo.orderHash).to.be.equal(expectedCancelledOrderHash);
- expect(cancelledOrderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(
- expectedCancelledTakerAssetFilledAmount,
- );
- expect(cancelledOrderInfo.orderStatus).to.be.equal(expectedCancelledOrderStatus);
-
- const expectedExpiredOrderHash = orderHashUtils.getOrderHashHex(expiredOrder);
- const expectedExpiredTakerAssetFilledAmount = new BigNumber(0);
- const expectedExpiredOrderStatus = OrderStatus.EXPIRED;
- const expiredOrderInfo = ordersInfo[4];
- expect(expiredOrderInfo.orderHash).to.be.equal(expectedExpiredOrderHash);
- expect(expiredOrderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(
- expectedExpiredTakerAssetFilledAmount,
- );
- expect(expiredOrderInfo.orderStatus).to.be.equal(expectedExpiredOrderStatus);
- });
- });
- });
-}); // tslint:disable-line:max-file-line-count
diff --git a/packages/contracts/test/extensions/forwarder.ts b/packages/contracts/test/extensions/forwarder.ts
deleted file mode 100644
index c006be0fe..000000000
--- a/packages/contracts/test/extensions/forwarder.ts
+++ /dev/null
@@ -1,1282 +0,0 @@
-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 { DummyERC20TokenContract } from '../../generated-wrappers/dummy_erc20_token';
-import { DummyERC721TokenContract } from '../../generated-wrappers/dummy_erc721_token';
-import { ExchangeContract } from '../../generated-wrappers/exchange';
-import { ForwarderContract } from '../../generated-wrappers/forwarder';
-import { WETH9Contract } from '../../generated-wrappers/weth9';
-import { artifacts } from '../../src/artifacts';
-import {
- expectContractCreationFailedAsync,
- expectTransactionFailedAsync,
- sendTransactionResult,
-} from '../utils/assertions';
-import { chaiSetup } from '../utils/chai_setup';
-import { constants } from '../utils/constants';
-import { ERC20Wrapper } from '../utils/erc20_wrapper';
-import { ERC721Wrapper } from '../utils/erc721_wrapper';
-import { ExchangeWrapper } from '../utils/exchange_wrapper';
-import { ForwarderWrapper } from '../utils/forwarder_wrapper';
-import { OrderFactory } from '../utils/order_factory';
-import { ContractName, ERC20BalancesByOwner } from '../utils/types';
-import { provider, txDefaults, web3Wrapper } from '../utils/web3_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 otherAddress: 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, otherAddress] = 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(artifacts.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(
- artifacts.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(
- artifacts.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/packages/contracts/test/extensions/order_validator.ts b/packages/contracts/test/extensions/order_validator.ts
deleted file mode 100644
index 37d7c4c5a..000000000
--- a/packages/contracts/test/extensions/order_validator.ts
+++ /dev/null
@@ -1,603 +0,0 @@
-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 { DummyERC20TokenContract } from '../../generated-wrappers/dummy_erc20_token';
-import { DummyERC721TokenContract } from '../../generated-wrappers/dummy_erc721_token';
-import { ERC20ProxyContract } from '../../generated-wrappers/erc20_proxy';
-import { ERC721ProxyContract } from '../../generated-wrappers/erc721_proxy';
-import { ExchangeContract } from '../../generated-wrappers/exchange';
-import { OrderValidatorContract } from '../../generated-wrappers/order_validator';
-import { artifacts } from '../../src/artifacts';
-import { chaiSetup } from '../utils/chai_setup';
-import { constants } from '../utils/constants';
-import { ERC20Wrapper } from '../utils/erc20_wrapper';
-import { ERC721Wrapper } from '../utils/erc721_wrapper';
-import { ExchangeWrapper } from '../utils/exchange_wrapper';
-import { OrderFactory } from '../utils/order_factory';
-import { OrderStatus } from '../utils/types';
-import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper';
-
-chaiSetup.configure();
-const expect = chai.expect;
-const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
-
-describe('OrderValidator', () => {
- let makerAddress: string;
- let owner: string;
- let takerAddress: string;
- let erc20AssetData: string;
- let erc721AssetData: string;
-
- let erc20Token: DummyERC20TokenContract;
- let zrxToken: DummyERC20TokenContract;
- let erc721Token: DummyERC721TokenContract;
- let exchange: ExchangeContract;
- let orderValidator: OrderValidatorContract;
- let erc20Proxy: ERC20ProxyContract;
- let erc721Proxy: ERC721ProxyContract;
-
- let signedOrder: SignedOrder;
- let signedOrder2: SignedOrder;
- let orderFactory: OrderFactory;
-
- const tokenId = new BigNumber(123456789);
- const tokenId2 = new BigNumber(987654321);
- const ERC721_BALANCE = new BigNumber(1);
- const ERC721_ALLOWANCE = new BigNumber(1);
-
- before(async () => {
- await blockchainLifecycle.startAsync();
- });
- after(async () => {
- await blockchainLifecycle.revertAsync();
- });
-
- before(async () => {
- const accounts = await web3Wrapper.getAvailableAddressesAsync();
- const usedAddresses = ([owner, makerAddress, takerAddress] = _.slice(accounts, 0, 3));
-
- const erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner);
- const erc721Wrapper = new ERC721Wrapper(provider, usedAddresses, owner);
-
- const numDummyErc20ToDeploy = 2;
- [erc20Token, zrxToken] = await erc20Wrapper.deployDummyTokensAsync(
- numDummyErc20ToDeploy,
- constants.DUMMY_TOKEN_DECIMALS,
- );
- erc20Proxy = await erc20Wrapper.deployProxyAsync();
-
- [erc721Token] = await erc721Wrapper.deployDummyTokensAsync();
- erc721Proxy = await erc721Wrapper.deployProxyAsync();
-
- const zrxAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address);
- exchange = await ExchangeContract.deployFrom0xArtifactAsync(
- artifacts.Exchange,
- provider,
- txDefaults,
- zrxAssetData,
- );
- const exchangeWrapper = new ExchangeWrapper(exchange, provider);
- await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner);
- await exchangeWrapper.registerAssetProxyAsync(erc721Proxy.address, owner);
-
- orderValidator = await OrderValidatorContract.deployFrom0xArtifactAsync(
- artifacts.OrderValidator,
- provider,
- txDefaults,
- exchange.address,
- zrxAssetData,
- );
-
- erc20AssetData = assetDataUtils.encodeERC20AssetData(erc20Token.address);
- erc721AssetData = assetDataUtils.encodeERC721AssetData(erc721Token.address, tokenId);
- const defaultOrderParams = {
- ...constants.STATIC_ORDER_PARAMS,
- exchangeAddress: exchange.address,
- makerAddress,
- feeRecipientAddress: constants.NULL_ADDRESS,
- makerAssetData: erc20AssetData,
- takerAssetData: erc721AssetData,
- };
- const privateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddress)];
- orderFactory = new OrderFactory(privateKey, defaultOrderParams);
- });
-
- beforeEach(async () => {
- await blockchainLifecycle.startAsync();
- });
- afterEach(async () => {
- await blockchainLifecycle.revertAsync();
- });
-
- describe('getBalanceAndAllowance', () => {
- describe('getERC721TokenOwner', async () => {
- it('should return the null address when tokenId is not owned', async () => {
- const tokenOwner = await orderValidator.getERC721TokenOwner.callAsync(makerAddress, tokenId);
- expect(tokenOwner).to.be.equal(constants.NULL_ADDRESS);
- });
- it('should return the owner address when tokenId is owned', async () => {
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc721Token.mint.sendTransactionAsync(makerAddress, tokenId),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const tokenOwner = await orderValidator.getERC721TokenOwner.callAsync(erc721Token.address, tokenId);
- expect(tokenOwner).to.be.equal(makerAddress);
- });
- });
- describe('ERC20 assetData', () => {
- it('should return the correct balances and allowances when both values are 0', async () => {
- const [newBalance, newAllowance] = await orderValidator.getBalanceAndAllowance.callAsync(
- makerAddress,
- erc20AssetData,
- );
- expect(constants.ZERO_AMOUNT).to.be.bignumber.equal(newBalance);
- expect(constants.ZERO_AMOUNT).to.be.bignumber.equal(newAllowance);
- });
- it('should return the correct balance and allowance when both values are non-zero', async () => {
- const balance = new BigNumber(123);
- const allowance = new BigNumber(456);
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc20Token.setBalance.sendTransactionAsync(makerAddress, balance),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc20Token.approve.sendTransactionAsync(erc20Proxy.address, allowance, {
- from: makerAddress,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const [newBalance, newAllowance] = await orderValidator.getBalanceAndAllowance.callAsync(
- makerAddress,
- erc20AssetData,
- );
- expect(balance).to.be.bignumber.equal(newBalance);
- expect(allowance).to.be.bignumber.equal(newAllowance);
- });
- });
- describe('ERC721 assetData', () => {
- it('should return a balance of 0 when the tokenId is not owned by target', async () => {
- const [newBalance] = await orderValidator.getBalanceAndAllowance.callAsync(
- makerAddress,
- erc721AssetData,
- );
- expect(newBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- });
- it('should return an allowance of 0 when no approval is set', async () => {
- const [, newAllowance] = await orderValidator.getBalanceAndAllowance.callAsync(
- makerAddress,
- erc721AssetData,
- );
- expect(newAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- });
- it('should return a balance of 1 when the tokenId is owned by target', async () => {
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc721Token.mint.sendTransactionAsync(makerAddress, tokenId),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const [newBalance] = await orderValidator.getBalanceAndAllowance.callAsync(
- makerAddress,
- erc721AssetData,
- );
- expect(newBalance).to.be.bignumber.equal(ERC721_BALANCE);
- });
- it('should return an allowance of 1 when ERC721Proxy is approved for all', async () => {
- const isApproved = true;
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc721Token.setApprovalForAll.sendTransactionAsync(erc721Proxy.address, isApproved, {
- from: makerAddress,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const [, newAllowance] = await orderValidator.getBalanceAndAllowance.callAsync(
- makerAddress,
- erc721AssetData,
- );
- expect(newAllowance).to.be.bignumber.equal(ERC721_ALLOWANCE);
- });
- it('should return an allowance of 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/packages/contracts/test/global_hooks.ts b/packages/contracts/test/global_hooks.ts
deleted file mode 100644
index 2e9ac9e21..000000000
--- a/packages/contracts/test/global_hooks.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-import { env, EnvVars } from '@0x/dev-utils';
-
-import { coverage } from './utils/coverage';
-import { profiler } from './utils/profiler';
-
-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();
- }
-});
diff --git a/packages/contracts/test/libraries/lib_bytes.ts b/packages/contracts/test/libraries/lib_bytes.ts
deleted file mode 100644
index b1a389f00..000000000
--- a/packages/contracts/test/libraries/lib_bytes.ts
+++ /dev/null
@@ -1,871 +0,0 @@
-import { BlockchainLifecycle } from '@0x/dev-utils';
-import { generatePseudoRandomSalt } from '@0x/order-utils';
-import { RevertReason } from '@0x/types';
-import { BigNumber } from '@0x/utils';
-import BN = require('bn.js');
-import * as chai from 'chai';
-import ethUtil = require('ethereumjs-util');
-import * as _ from 'lodash';
-
-import { TestLibBytesContract } from '../../generated-wrappers/test_lib_bytes';
-import { artifacts } from '../../src/artifacts';
-import { expectContractCallFailedAsync } from '../utils/assertions';
-import { chaiSetup } from '../utils/chai_setup';
-import { constants } from '../utils/constants';
-import { typeEncodingUtils } from '../utils/type_encoding_utils';
-import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper';
-
-chaiSetup.configure();
-const expect = chai.expect;
-const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
-
-// BUG: Ideally we would use Buffer.from(memory).toString('hex')
-// https://github.com/Microsoft/TypeScript/issues/23155
-const toHex = (buf: Uint8Array): string => buf.reduce((a, v) => a + ('00' + v.toString(16)).slice(-2), '0x');
-
-const fromHex = (str: string): Uint8Array => Uint8Array.from(Buffer.from(str.slice(2), 'hex'));
-
-describe('LibBytes', () => {
- let libBytes: TestLibBytesContract;
- const byteArrayShorterThan32Bytes = '0x012345';
- const byteArrayShorterThan20Bytes = byteArrayShorterThan32Bytes;
- const byteArrayLongerThan32Bytes =
- '0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef';
- const byteArrayLongerThan32BytesFirstBytesSwapped =
- '0x2301456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef';
- const byteArrayLongerThan32BytesLastBytesSwapped =
- '0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abefcd';
- let testAddress: string;
- let testAddressB: string;
- const testBytes32 = '0x102030405060708090a0b0c0d0e0f0102030405060708090a0b0c0d0e0f01020';
- const testBytes32B = '0x534877abd8443578526845cdfef020047528759477fedef87346527659aced32';
- const testUint256 = new BigNumber(testBytes32, 16);
- const testUint256B = new BigNumber(testBytes32B, 16);
- const testBytes4 = '0xabcdef12';
- const testByte = '0xab';
- let shortData: string;
- let shortTestBytes: string;
- let shortTestBytesAsBuffer: Buffer;
- let wordOfData: string;
- let wordOfTestBytes: string;
- let wordOfTestBytesAsBuffer: Buffer;
- let longData: string;
- let longTestBytes: string;
- let longTestBytesAsBuffer: Buffer;
-
- before(async () => {
- await blockchainLifecycle.startAsync();
- });
- after(async () => {
- await blockchainLifecycle.revertAsync();
- });
- before(async () => {
- // Setup accounts & addresses
- const accounts = await web3Wrapper.getAvailableAddressesAsync();
- testAddress = accounts[1];
- testAddressB = accounts[2];
- // Deploy LibBytes
- libBytes = await TestLibBytesContract.deployFrom0xArtifactAsync(artifacts.TestLibBytes, provider, txDefaults);
- // Verify lengths of test data
- const byteArrayShorterThan32BytesLength = ethUtil.toBuffer(byteArrayShorterThan32Bytes).byteLength;
- expect(byteArrayShorterThan32BytesLength).to.be.lessThan(32);
- const byteArrayLongerThan32BytesLength = ethUtil.toBuffer(byteArrayLongerThan32Bytes).byteLength;
- expect(byteArrayLongerThan32BytesLength).to.be.greaterThan(32);
- const testBytes32Length = ethUtil.toBuffer(testBytes32).byteLength;
- expect(testBytes32Length).to.be.equal(32);
- // Create short test bytes
- shortData = '0xffffaa';
- const encodedShortData = ethUtil.toBuffer(shortData);
- const shortDataLength = new BigNumber(encodedShortData.byteLength);
- const encodedShortDataLength = typeEncodingUtils.encodeUint256(shortDataLength);
- shortTestBytesAsBuffer = Buffer.concat([encodedShortDataLength, encodedShortData]);
- shortTestBytes = ethUtil.bufferToHex(shortTestBytesAsBuffer);
- // Create test bytes one word in length
- wordOfData = ethUtil.bufferToHex(typeEncodingUtils.encodeUint256(generatePseudoRandomSalt()));
- const encodedWordOfData = ethUtil.toBuffer(wordOfData);
- const wordOfDataLength = new BigNumber(encodedWordOfData.byteLength);
- const encodedWordOfDataLength = typeEncodingUtils.encodeUint256(wordOfDataLength);
- wordOfTestBytesAsBuffer = Buffer.concat([encodedWordOfDataLength, encodedWordOfData]);
- wordOfTestBytes = ethUtil.bufferToHex(wordOfTestBytesAsBuffer);
- // Create long test bytes (combines short test bytes with word of test bytes)
- longData = ethUtil.bufferToHex(Buffer.concat([encodedShortData, encodedWordOfData]));
- const longDataLength = new BigNumber(encodedShortData.byteLength + encodedWordOfData.byteLength);
- const encodedLongDataLength = typeEncodingUtils.encodeUint256(longDataLength);
- longTestBytesAsBuffer = Buffer.concat([encodedLongDataLength, encodedShortData, encodedWordOfData]);
- longTestBytes = ethUtil.bufferToHex(longTestBytesAsBuffer);
- });
- beforeEach(async () => {
- await blockchainLifecycle.startAsync();
- });
- afterEach(async () => {
- await blockchainLifecycle.revertAsync();
- });
-
- describe('popLastByte', () => {
- it('should revert if length is 0', async () => {
- return expectContractCallFailedAsync(
- libBytes.publicPopLastByte.callAsync(constants.NULL_BYTES),
- RevertReason.LibBytesGreaterThanZeroLengthRequired,
- );
- });
- it('should pop the last byte from the input and return it when array holds more than 1 byte', async () => {
- const [newBytes, poppedByte] = await libBytes.publicPopLastByte.callAsync(byteArrayLongerThan32Bytes);
- const expectedNewBytes = byteArrayLongerThan32Bytes.slice(0, -2);
- const expectedPoppedByte = `0x${byteArrayLongerThan32Bytes.slice(-2)}`;
- expect(newBytes).to.equal(expectedNewBytes);
- expect(poppedByte).to.equal(expectedPoppedByte);
- });
- it('should pop the last byte from the input and return it when array is exactly 1 byte', async () => {
- const [newBytes, poppedByte] = await libBytes.publicPopLastByte.callAsync(testByte);
- const expectedNewBytes = '0x';
- expect(newBytes).to.equal(expectedNewBytes);
- return expect(poppedByte).to.be.equal(testByte);
- });
- });
-
- describe('popLast20Bytes', () => {
- it('should revert if length is less than 20', async () => {
- return expectContractCallFailedAsync(
- libBytes.publicPopLast20Bytes.callAsync(byteArrayShorterThan20Bytes),
- RevertReason.LibBytesGreaterOrEqualTo20LengthRequired,
- );
- });
- it('should pop the last 20 bytes from the input and return it when array holds more than 20 bytes', async () => {
- const [newBytes, poppedAddress] = await libBytes.publicPopLast20Bytes.callAsync(byteArrayLongerThan32Bytes);
- const expectedNewBytes = byteArrayLongerThan32Bytes.slice(0, -40);
- const expectedPoppedAddress = `0x${byteArrayLongerThan32Bytes.slice(-40)}`;
- expect(newBytes).to.equal(expectedNewBytes);
- expect(poppedAddress).to.equal(expectedPoppedAddress);
- });
- it('should pop the last 20 bytes from the input and return it when array is exactly 20 bytes', async () => {
- const [newBytes, poppedAddress] = await libBytes.publicPopLast20Bytes.callAsync(testAddress);
- const expectedNewBytes = '0x';
- const expectedPoppedAddress = testAddress;
- expect(newBytes).to.equal(expectedNewBytes);
- expect(poppedAddress).to.equal(expectedPoppedAddress);
- });
- });
-
- describe('equals', () => {
- it('should return true if byte arrays are equal (both arrays < 32 bytes)', async () => {
- const isEqual = await libBytes.publicEquals.callAsync(
- byteArrayShorterThan32Bytes,
- byteArrayShorterThan32Bytes,
- );
- return expect(isEqual).to.be.true();
- });
- it('should return true if byte arrays are equal (both arrays > 32 bytes)', async () => {
- const isEqual = await libBytes.publicEquals.callAsync(
- byteArrayLongerThan32Bytes,
- byteArrayLongerThan32Bytes,
- );
- return expect(isEqual).to.be.true();
- });
- it('should return false if byte arrays are not equal (first array < 32 bytes, second array > 32 bytes)', async () => {
- const isEqual = await libBytes.publicEquals.callAsync(
- byteArrayShorterThan32Bytes,
- byteArrayLongerThan32Bytes,
- );
- return expect(isEqual).to.be.false();
- });
- it('should return false if byte arrays are not equal (first array > 32 bytes, second array < 32 bytes)', async () => {
- const isEqual = await libBytes.publicEquals.callAsync(
- byteArrayLongerThan32Bytes,
- byteArrayShorterThan32Bytes,
- );
- return expect(isEqual).to.be.false();
- });
- it('should return false if byte arrays are not equal (same length, but a byte in first word differs)', async () => {
- const isEqual = await libBytes.publicEquals.callAsync(
- byteArrayLongerThan32BytesFirstBytesSwapped,
- byteArrayLongerThan32Bytes,
- );
- return expect(isEqual).to.be.false();
- });
- it('should return false if byte arrays are not equal (same length, but a byte in last word differs)', async () => {
- const isEqual = await libBytes.publicEquals.callAsync(
- byteArrayLongerThan32BytesLastBytesSwapped,
- byteArrayLongerThan32Bytes,
- );
- return expect(isEqual).to.be.false();
- });
-
- describe('should ignore trailing data', () => {
- it('should return true when both < 32 bytes', async () => {
- const isEqual = await libBytes.publicEqualsPop1.callAsync('0x0102', '0x0103');
- return expect(isEqual).to.be.true();
- });
- });
- });
-
- describe('deepCopyBytes', () => {
- it('should revert if dest is shorter than source', async () => {
- return expectContractCallFailedAsync(
- libBytes.publicDeepCopyBytes.callAsync(byteArrayShorterThan32Bytes, byteArrayLongerThan32Bytes),
- RevertReason.LibBytesGreaterOrEqualToSourceBytesLengthRequired,
- );
- });
- it('should overwrite dest with source if source and dest have equal length', async () => {
- const zeroedByteArrayLongerThan32Bytes = `0x${_.repeat('0', byteArrayLongerThan32Bytes.length - 2)}`;
- const zeroedBytesAfterCopy = await libBytes.publicDeepCopyBytes.callAsync(
- zeroedByteArrayLongerThan32Bytes,
- byteArrayLongerThan32Bytes,
- );
- return expect(zeroedBytesAfterCopy).to.be.equal(byteArrayLongerThan32Bytes);
- });
- it('should overwrite the leftmost len(source) bytes of dest if dest is larger than source', async () => {
- const zeroedByteArrayLongerThan32Bytes = `0x${_.repeat('0', byteArrayLongerThan32Bytes.length * 2)}`;
- const zeroedBytesAfterCopy = await libBytes.publicDeepCopyBytes.callAsync(
- zeroedByteArrayLongerThan32Bytes,
- byteArrayLongerThan32Bytes,
- );
- const copiedBytes = zeroedBytesAfterCopy.slice(0, byteArrayLongerThan32Bytes.length);
- return expect(copiedBytes).to.be.equal(byteArrayLongerThan32Bytes);
- });
- it('should not overwrite the rightmost bytes of dest if dest is larger than source', async () => {
- const zeroedByteArrayLongerThan32Bytes = `0x${_.repeat('0', byteArrayLongerThan32Bytes.length * 2)}`;
- const zeroedBytesAfterCopy = await libBytes.publicDeepCopyBytes.callAsync(
- zeroedByteArrayLongerThan32Bytes,
- byteArrayLongerThan32Bytes,
- );
- const expectedNotCopiedBytes = zeroedByteArrayLongerThan32Bytes.slice(byteArrayLongerThan32Bytes.length);
- const notCopiedBytes = zeroedBytesAfterCopy.slice(byteArrayLongerThan32Bytes.length);
- return expect(notCopiedBytes).to.be.equal(expectedNotCopiedBytes);
- });
- });
-
- describe('readAddress', () => {
- it('should successfully read address when the address takes up the whole array', async () => {
- const byteArray = ethUtil.addHexPrefix(testAddress);
- const testAddressOffset = new BigNumber(0);
- const address = await libBytes.publicReadAddress.callAsync(byteArray, testAddressOffset);
- return expect(address).to.be.equal(testAddress);
- });
- it('should successfully read address when it is offset in the array', async () => {
- const addressByteArrayBuffer = ethUtil.toBuffer(testAddress);
- const prefixByteArrayBuffer = ethUtil.toBuffer('0xabcdef');
- const combinedByteArrayBuffer = Buffer.concat([prefixByteArrayBuffer, addressByteArrayBuffer]);
- const combinedByteArray = ethUtil.bufferToHex(combinedByteArrayBuffer);
- const testAddressOffset = new BigNumber(prefixByteArrayBuffer.byteLength);
- const address = await libBytes.publicReadAddress.callAsync(combinedByteArray, testAddressOffset);
- return expect(address).to.be.equal(testAddress);
- });
- it('should fail if the byte array is too short to hold an address', async () => {
- const shortByteArray = '0xabcdef';
- const offset = new BigNumber(0);
- return expectContractCallFailedAsync(
- libBytes.publicReadAddress.callAsync(shortByteArray, offset),
- RevertReason.LibBytesGreaterOrEqualTo20LengthRequired,
- );
- });
- it('should fail if the length between the offset and end of the byte array is too short to hold an address', async () => {
- const byteArray = testAddress;
- const badOffset = new BigNumber(ethUtil.toBuffer(byteArray).byteLength);
- return expectContractCallFailedAsync(
- libBytes.publicReadAddress.callAsync(byteArray, badOffset),
- RevertReason.LibBytesGreaterOrEqualTo20LengthRequired,
- );
- });
- });
-
- describe('writeAddress', () => {
- it('should successfully write address when the address takes up the whole array', async () => {
- const byteArray = testAddress;
- const testAddressOffset = new BigNumber(0);
- const newByteArray = await libBytes.publicWriteAddress.callAsync(
- byteArray,
- testAddressOffset,
- testAddressB,
- );
- return expect(newByteArray).to.be.equal(testAddressB);
- });
- it('should successfully write address when it is offset in the array', async () => {
- const addressByteArrayBuffer = ethUtil.toBuffer(testAddress);
- const prefixByteArrayBuffer = ethUtil.toBuffer('0xabcdef');
- const combinedByteArrayBuffer = Buffer.concat([prefixByteArrayBuffer, addressByteArrayBuffer]);
- const combinedByteArray = ethUtil.bufferToHex(combinedByteArrayBuffer);
- const testAddressOffset = new BigNumber(prefixByteArrayBuffer.byteLength);
- const newByteArray = await libBytes.publicWriteAddress.callAsync(
- combinedByteArray,
- testAddressOffset,
- testAddressB,
- );
- const newByteArrayBuffer = ethUtil.toBuffer(newByteArray);
- const addressFromOffsetBuffer = newByteArrayBuffer.slice(prefixByteArrayBuffer.byteLength);
- const addressFromOffset = ethUtil.addHexPrefix(ethUtil.bufferToHex(addressFromOffsetBuffer));
- return expect(addressFromOffset).to.be.equal(testAddressB);
- });
- it('should fail if the byte array is too short to hold an address', async () => {
- const offset = new BigNumber(0);
- return expectContractCallFailedAsync(
- libBytes.publicWriteAddress.callAsync(byteArrayShorterThan20Bytes, offset, testAddress),
- RevertReason.LibBytesGreaterOrEqualTo20LengthRequired,
- );
- });
- it('should fail if the length between the offset and end of the byte array is too short to hold an address', async () => {
- const byteArray = byteArrayLongerThan32Bytes;
- const badOffset = new BigNumber(ethUtil.toBuffer(byteArray).byteLength);
- return expectContractCallFailedAsync(
- libBytes.publicWriteAddress.callAsync(byteArray, badOffset, testAddress),
- RevertReason.LibBytesGreaterOrEqualTo20LengthRequired,
- );
- });
- });
-
- describe('readBytes32', () => {
- it('should successfully read bytes32 when the bytes32 takes up the whole array', async () => {
- const testBytes32Offset = new BigNumber(0);
- const bytes32 = await libBytes.publicReadBytes32.callAsync(testBytes32, testBytes32Offset);
- return expect(bytes32).to.be.equal(testBytes32);
- });
- it('should successfully read bytes32 when it is offset in the array', async () => {
- const bytes32ByteArrayBuffer = ethUtil.toBuffer(testBytes32);
- const prefixByteArrayBuffer = ethUtil.toBuffer('0xabcdef');
- const combinedByteArrayBuffer = Buffer.concat([prefixByteArrayBuffer, bytes32ByteArrayBuffer]);
- const combinedByteArray = ethUtil.bufferToHex(combinedByteArrayBuffer);
- const testBytes32Offset = new BigNumber(prefixByteArrayBuffer.byteLength);
- const bytes32 = await libBytes.publicReadBytes32.callAsync(combinedByteArray, testBytes32Offset);
- return expect(bytes32).to.be.equal(testBytes32);
- });
- it('should fail if the byte array is too short to hold a bytes32', async () => {
- const offset = new BigNumber(0);
- return expectContractCallFailedAsync(
- libBytes.publicReadBytes32.callAsync(byteArrayShorterThan32Bytes, offset),
- RevertReason.LibBytesGreaterOrEqualTo32LengthRequired,
- );
- });
- it('should fail if the length between the offset and end of the byte array is too short to hold a bytes32', async () => {
- const badOffset = new BigNumber(ethUtil.toBuffer(testBytes32).byteLength);
- return expectContractCallFailedAsync(
- libBytes.publicReadBytes32.callAsync(testBytes32, badOffset),
- RevertReason.LibBytesGreaterOrEqualTo32LengthRequired,
- );
- });
- });
-
- describe('writeBytes32', () => {
- it('should successfully write bytes32 when the address takes up the whole array', async () => {
- const byteArray = testBytes32;
- const testBytes32Offset = new BigNumber(0);
- const newByteArray = await libBytes.publicWriteBytes32.callAsync(
- byteArray,
- testBytes32Offset,
- testBytes32B,
- );
- return expect(newByteArray).to.be.equal(testBytes32B);
- });
- it('should successfully write bytes32 when it is offset in the array', async () => {
- const bytes32ByteArrayBuffer = ethUtil.toBuffer(testBytes32);
- const prefixByteArrayBuffer = ethUtil.toBuffer('0xabcdef');
- const combinedByteArrayBuffer = Buffer.concat([prefixByteArrayBuffer, bytes32ByteArrayBuffer]);
- const combinedByteArray = ethUtil.bufferToHex(combinedByteArrayBuffer);
- const testBytes32Offset = new BigNumber(prefixByteArrayBuffer.byteLength);
- const newByteArray = await libBytes.publicWriteBytes32.callAsync(
- combinedByteArray,
- testBytes32Offset,
- testBytes32B,
- );
- const newByteArrayBuffer = ethUtil.toBuffer(newByteArray);
- const bytes32FromOffsetBuffer = newByteArrayBuffer.slice(prefixByteArrayBuffer.byteLength);
- const bytes32FromOffset = ethUtil.addHexPrefix(ethUtil.bufferToHex(bytes32FromOffsetBuffer));
- return expect(bytes32FromOffset).to.be.equal(testBytes32B);
- });
- it('should fail if the byte array is too short to hold a bytes32', async () => {
- const offset = new BigNumber(0);
- return expectContractCallFailedAsync(
- libBytes.publicWriteBytes32.callAsync(byteArrayShorterThan32Bytes, offset, testBytes32),
- RevertReason.LibBytesGreaterOrEqualTo32LengthRequired,
- );
- });
- it('should fail if the length between the offset and end of the byte array is too short to hold a bytes32', async () => {
- const byteArray = byteArrayLongerThan32Bytes;
- const badOffset = new BigNumber(ethUtil.toBuffer(byteArray).byteLength);
- return expectContractCallFailedAsync(
- libBytes.publicWriteBytes32.callAsync(byteArray, badOffset, testBytes32),
- RevertReason.LibBytesGreaterOrEqualTo32LengthRequired,
- );
- });
- });
-
- describe('readUint256', () => {
- it('should successfully read uint256 when the uint256 takes up the whole array', async () => {
- const formattedTestUint256 = new BN(testUint256.toString(10));
- const testUint256AsBuffer = ethUtil.toBuffer(formattedTestUint256);
- const byteArray = ethUtil.bufferToHex(testUint256AsBuffer);
- const testUint256Offset = new BigNumber(0);
- const uint256 = await libBytes.publicReadUint256.callAsync(byteArray, testUint256Offset);
- return expect(uint256).to.bignumber.equal(testUint256);
- });
- it('should successfully read uint256 when it is offset in the array', async () => {
- const prefixByteArrayBuffer = ethUtil.toBuffer('0xabcdef');
- const formattedTestUint256 = new BN(testUint256.toString(10));
- const testUint256AsBuffer = ethUtil.toBuffer(formattedTestUint256);
- const combinedByteArrayBuffer = Buffer.concat([prefixByteArrayBuffer, testUint256AsBuffer]);
- const combinedByteArray = ethUtil.bufferToHex(combinedByteArrayBuffer);
- const testUint256Offset = new BigNumber(prefixByteArrayBuffer.byteLength);
- const uint256 = await libBytes.publicReadUint256.callAsync(combinedByteArray, testUint256Offset);
- return expect(uint256).to.bignumber.equal(testUint256);
- });
- it('should fail if the byte array is too short to hold a uint256', async () => {
- const offset = new BigNumber(0);
- return expectContractCallFailedAsync(
- libBytes.publicReadUint256.callAsync(byteArrayShorterThan32Bytes, offset),
- RevertReason.LibBytesGreaterOrEqualTo32LengthRequired,
- );
- });
- it('should fail if the length between the offset and end of the byte array is too short to hold a uint256', async () => {
- const formattedTestUint256 = new BN(testUint256.toString(10));
- const testUint256AsBuffer = ethUtil.toBuffer(formattedTestUint256);
- const byteArray = ethUtil.bufferToHex(testUint256AsBuffer);
- const badOffset = new BigNumber(testUint256AsBuffer.byteLength);
- return expectContractCallFailedAsync(
- libBytes.publicReadUint256.callAsync(byteArray, badOffset),
- RevertReason.LibBytesGreaterOrEqualTo32LengthRequired,
- );
- });
- });
-
- describe('writeUint256', () => {
- it('should successfully write uint256 when the address takes up the whole array', async () => {
- const byteArray = testBytes32;
- const testUint256Offset = new BigNumber(0);
- const newByteArray = await libBytes.publicWriteUint256.callAsync(
- byteArray,
- testUint256Offset,
- testUint256B,
- );
- const newByteArrayAsUint256 = new BigNumber(newByteArray, 16);
- return expect(newByteArrayAsUint256).to.be.bignumber.equal(testUint256B);
- });
- it('should successfully write uint256 when it is offset in the array', async () => {
- const bytes32ByteArrayBuffer = ethUtil.toBuffer(testBytes32);
- const prefixByteArrayBuffer = ethUtil.toBuffer('0xabcdef');
- const combinedByteArrayBuffer = Buffer.concat([prefixByteArrayBuffer, bytes32ByteArrayBuffer]);
- const combinedByteArray = ethUtil.bufferToHex(combinedByteArrayBuffer);
- const testUint256Offset = new BigNumber(prefixByteArrayBuffer.byteLength);
- const newByteArray = await libBytes.publicWriteUint256.callAsync(
- combinedByteArray,
- testUint256Offset,
- testUint256B,
- );
- const newByteArrayBuffer = ethUtil.toBuffer(newByteArray);
- const uint256FromOffsetBuffer = newByteArrayBuffer.slice(prefixByteArrayBuffer.byteLength);
- const uint256FromOffset = new BigNumber(
- ethUtil.addHexPrefix(ethUtil.bufferToHex(uint256FromOffsetBuffer)),
- 16,
- );
- return expect(uint256FromOffset).to.be.bignumber.equal(testUint256B);
- });
- it('should fail if the byte array is too short to hold a uint256', async () => {
- const offset = new BigNumber(0);
- return expectContractCallFailedAsync(
- libBytes.publicWriteUint256.callAsync(byteArrayShorterThan32Bytes, offset, testUint256),
- RevertReason.LibBytesGreaterOrEqualTo32LengthRequired,
- );
- });
- it('should fail if the length between the offset and end of the byte array is too short to hold a uint256', async () => {
- const byteArray = byteArrayLongerThan32Bytes;
- const badOffset = new BigNumber(ethUtil.toBuffer(byteArray).byteLength);
- return expectContractCallFailedAsync(
- libBytes.publicWriteUint256.callAsync(byteArray, badOffset, testUint256),
- RevertReason.LibBytesGreaterOrEqualTo32LengthRequired,
- );
- });
- });
-
- describe('readBytes4', () => {
- // AssertionError: expected promise to be rejected with an error including 'revert' but it was fulfilled with '0x08c379a0'
- it('should revert if byte array has a length < 4', async () => {
- const byteArrayLessThan4Bytes = '0x010101';
- const offset = new BigNumber(0);
- return expectContractCallFailedAsync(
- libBytes.publicReadBytes4.callAsync(byteArrayLessThan4Bytes, offset),
- RevertReason.LibBytesGreaterOrEqualTo4LengthRequired,
- );
- });
- it('should return the first 4 bytes of a byte array of arbitrary length', async () => {
- const first4Bytes = await libBytes.publicReadBytes4.callAsync(byteArrayLongerThan32Bytes, new BigNumber(0));
- const expectedFirst4Bytes = byteArrayLongerThan32Bytes.slice(0, 10);
- expect(first4Bytes).to.equal(expectedFirst4Bytes);
- });
- it('should successfully read bytes4 when the bytes4 takes up the whole array', async () => {
- const testBytes4Offset = new BigNumber(0);
- const bytes4 = await libBytes.publicReadBytes4.callAsync(testBytes4, testBytes4Offset);
- return expect(bytes4).to.be.equal(testBytes4);
- });
- it('should successfully read bytes4 when it is offset in the array', async () => {
- const bytes4ByteArrayBuffer = ethUtil.toBuffer(testBytes4);
- const prefixByteArrayBuffer = ethUtil.toBuffer('0xabcdef');
- const combinedByteArrayBuffer = Buffer.concat([prefixByteArrayBuffer, bytes4ByteArrayBuffer]);
- const combinedByteArray = ethUtil.bufferToHex(combinedByteArrayBuffer);
- const testBytes4Offset = new BigNumber(prefixByteArrayBuffer.byteLength);
- const bytes4 = await libBytes.publicReadBytes4.callAsync(combinedByteArray, testBytes4Offset);
- return expect(bytes4).to.be.equal(testBytes4);
- });
- it('should fail if the length between the offset and end of the byte array is too short to hold a bytes4', async () => {
- const badOffset = new BigNumber(ethUtil.toBuffer(testBytes4).byteLength);
- return expectContractCallFailedAsync(
- libBytes.publicReadBytes4.callAsync(testBytes4, badOffset),
- RevertReason.LibBytesGreaterOrEqualTo4LengthRequired,
- );
- });
- });
-
- describe('readBytesWithLength', () => {
- it('should successfully read short, nested array of bytes when it takes up the whole array', async () => {
- const testBytesOffset = new BigNumber(0);
- const bytes = await libBytes.publicReadBytesWithLength.callAsync(shortTestBytes, testBytesOffset);
- return expect(bytes).to.be.equal(shortData);
- });
- it('should successfully read short, nested array of bytes when it is offset in the array', async () => {
- const prefixByteArrayBuffer = ethUtil.toBuffer('0xabcdef');
- const combinedByteArrayBuffer = Buffer.concat([prefixByteArrayBuffer, shortTestBytesAsBuffer]);
- const combinedByteArray = ethUtil.bufferToHex(combinedByteArrayBuffer);
- const testUint256Offset = new BigNumber(prefixByteArrayBuffer.byteLength);
- const bytes = await libBytes.publicReadBytesWithLength.callAsync(combinedByteArray, testUint256Offset);
- return expect(bytes).to.be.equal(shortData);
- });
- it('should successfully read a nested array of bytes - one word in length - when it takes up the whole array', async () => {
- const testBytesOffset = new BigNumber(0);
- const bytes = await libBytes.publicReadBytesWithLength.callAsync(wordOfTestBytes, testBytesOffset);
- return expect(bytes).to.be.equal(wordOfData);
- });
- it('should successfully read a nested array of bytes - one word in length - when it is offset in the array', async () => {
- const prefixByteArrayBuffer = ethUtil.toBuffer('0xabcdef');
- const combinedByteArrayBuffer = Buffer.concat([prefixByteArrayBuffer, wordOfTestBytesAsBuffer]);
- const combinedByteArray = ethUtil.bufferToHex(combinedByteArrayBuffer);
- const testUint256Offset = new BigNumber(prefixByteArrayBuffer.byteLength);
- const bytes = await libBytes.publicReadBytesWithLength.callAsync(combinedByteArray, testUint256Offset);
- return expect(bytes).to.be.equal(wordOfData);
- });
- it('should successfully read long, nested array of bytes when it takes up the whole array', async () => {
- const testBytesOffset = new BigNumber(0);
- const bytes = await libBytes.publicReadBytesWithLength.callAsync(longTestBytes, testBytesOffset);
- return expect(bytes).to.be.equal(longData);
- });
- it('should successfully read long, nested array of bytes when it is offset in the array', async () => {
- const prefixByteArrayBuffer = ethUtil.toBuffer('0xabcdef');
- const combinedByteArrayBuffer = Buffer.concat([prefixByteArrayBuffer, longTestBytesAsBuffer]);
- const combinedByteArray = ethUtil.bufferToHex(combinedByteArrayBuffer);
- const testUint256Offset = new BigNumber(prefixByteArrayBuffer.byteLength);
- const bytes = await libBytes.publicReadBytesWithLength.callAsync(combinedByteArray, testUint256Offset);
- return expect(bytes).to.be.equal(longData);
- });
- it('should fail if the byte array is too short to hold the length of a nested byte array', async () => {
- // The length of the nested array is 32 bytes. By storing less than 32 bytes, a length cannot be read.
- const offset = new BigNumber(0);
- return expectContractCallFailedAsync(
- libBytes.publicReadBytesWithLength.callAsync(byteArrayShorterThan32Bytes, offset),
- RevertReason.LibBytesGreaterOrEqualTo32LengthRequired,
- );
- });
- it('should fail if we store a nested byte array length, without a nested byte array', async () => {
- const offset = new BigNumber(0);
- return expectContractCallFailedAsync(
- libBytes.publicReadBytesWithLength.callAsync(testBytes32, offset),
- RevertReason.LibBytesGreaterOrEqualToNestedBytesLengthRequired,
- );
- });
- it('should fail if the length between the offset and end of the byte array is too short to hold the length of a nested byte array', async () => {
- const badOffset = new BigNumber(ethUtil.toBuffer(byteArrayShorterThan32Bytes).byteLength);
- return expectContractCallFailedAsync(
- libBytes.publicReadBytesWithLength.callAsync(byteArrayShorterThan32Bytes, badOffset),
- RevertReason.LibBytesGreaterOrEqualTo32LengthRequired,
- );
- });
- it('should fail if the length between the offset and end of the byte array is too short to hold the nested byte array', async () => {
- const badOffset = new BigNumber(ethUtil.toBuffer(testBytes32).byteLength);
- return expectContractCallFailedAsync(
- libBytes.publicReadBytesWithLength.callAsync(testBytes32, badOffset),
- RevertReason.LibBytesGreaterOrEqualTo32LengthRequired,
- );
- });
- });
-
- describe('writeBytesWithLength', () => {
- it('should successfully write short, nested array of bytes when it takes up the whole array', async () => {
- const testBytesOffset = new BigNumber(0);
- const emptyByteArray = ethUtil.bufferToHex(new Buffer(shortTestBytesAsBuffer.byteLength));
- const bytesWritten = await libBytes.publicWriteBytesWithLength.callAsync(
- emptyByteArray,
- testBytesOffset,
- shortData,
- );
- const bytesRead = await libBytes.publicReadBytesWithLength.callAsync(bytesWritten, testBytesOffset);
- return expect(bytesRead).to.be.equal(shortData);
- });
- it('should successfully write short, nested array of bytes when it is offset in the array', async () => {
- // Write a prefix to the array
- const prefixData = '0xabcdef';
- const prefixDataAsBuffer = ethUtil.toBuffer(prefixData);
- const prefixOffset = new BigNumber(0);
- const emptyByteArray = ethUtil.bufferToHex(
- new Buffer(prefixDataAsBuffer.byteLength + shortTestBytesAsBuffer.byteLength),
- );
- let bytesWritten = await libBytes.publicWriteBytesWithLength.callAsync(
- emptyByteArray,
- prefixOffset,
- prefixData,
- );
- // Write data after prefix
- const testBytesOffset = new BigNumber(prefixDataAsBuffer.byteLength);
- bytesWritten = await libBytes.publicWriteBytesWithLength.callAsync(
- bytesWritten,
- testBytesOffset,
- shortData,
- );
- // Read data after prefix and validate
- const bytes = await libBytes.publicReadBytesWithLength.callAsync(bytesWritten, testBytesOffset);
- return expect(bytes).to.be.equal(shortData);
- });
- it('should successfully write a nested array of bytes - one word in length - when it takes up the whole array', async () => {
- const testBytesOffset = new BigNumber(0);
- const emptyByteArray = ethUtil.bufferToHex(new Buffer(wordOfTestBytesAsBuffer.byteLength));
- const bytesWritten = await libBytes.publicWriteBytesWithLength.callAsync(
- emptyByteArray,
- testBytesOffset,
- wordOfData,
- );
- const bytesRead = await libBytes.publicReadBytesWithLength.callAsync(bytesWritten, testBytesOffset);
- return expect(bytesRead).to.be.equal(wordOfData);
- });
- it('should successfully write a nested array of bytes - one word in length - when it is offset in the array', async () => {
- // Write a prefix to the array
- const prefixData = '0xabcdef';
- const prefixDataAsBuffer = ethUtil.toBuffer(prefixData);
- const prefixOffset = new BigNumber(0);
- const emptyByteArray = ethUtil.bufferToHex(
- new Buffer(prefixDataAsBuffer.byteLength + wordOfTestBytesAsBuffer.byteLength),
- );
- let bytesWritten = await libBytes.publicWriteBytesWithLength.callAsync(
- emptyByteArray,
- prefixOffset,
- prefixData,
- );
- // Write data after prefix
- const testBytesOffset = new BigNumber(prefixDataAsBuffer.byteLength);
- bytesWritten = await libBytes.publicWriteBytesWithLength.callAsync(
- bytesWritten,
- testBytesOffset,
- wordOfData,
- );
- // Read data after prefix and validate
- const bytes = await libBytes.publicReadBytesWithLength.callAsync(bytesWritten, testBytesOffset);
- return expect(bytes).to.be.equal(wordOfData);
- });
- it('should successfully write a long, nested bytes when it takes up the whole array', async () => {
- const testBytesOffset = new BigNumber(0);
- const emptyByteArray = ethUtil.bufferToHex(new Buffer(longTestBytesAsBuffer.byteLength));
- const bytesWritten = await libBytes.publicWriteBytesWithLength.callAsync(
- emptyByteArray,
- testBytesOffset,
- longData,
- );
- const bytesRead = await libBytes.publicReadBytesWithLength.callAsync(bytesWritten, testBytesOffset);
- return expect(bytesRead).to.be.equal(longData);
- });
- it('should successfully write long, nested array of bytes when it is offset in the array', async () => {
- // Write a prefix to the array
- const prefixData = '0xabcdef';
- const prefixDataAsBuffer = ethUtil.toBuffer(prefixData);
- const prefixOffset = new BigNumber(0);
- const emptyByteArray = ethUtil.bufferToHex(
- new Buffer(prefixDataAsBuffer.byteLength + longTestBytesAsBuffer.byteLength),
- );
- let bytesWritten = await libBytes.publicWriteBytesWithLength.callAsync(
- emptyByteArray,
- prefixOffset,
- prefixData,
- );
- // Write data after prefix
- const testBytesOffset = new BigNumber(prefixDataAsBuffer.byteLength);
- bytesWritten = await libBytes.publicWriteBytesWithLength.callAsync(bytesWritten, testBytesOffset, longData);
- // Read data after prefix and validate
- const bytes = await libBytes.publicReadBytesWithLength.callAsync(bytesWritten, testBytesOffset);
- return expect(bytes).to.be.equal(longData);
- });
- it('should fail if the byte array is too short to hold the length of a nested byte array', async () => {
- const offset = new BigNumber(0);
- const emptyByteArray = ethUtil.bufferToHex(new Buffer(1));
- return expectContractCallFailedAsync(
- libBytes.publicWriteBytesWithLength.callAsync(emptyByteArray, offset, longData),
- RevertReason.LibBytesGreaterOrEqualToNestedBytesLengthRequired,
- );
- });
- it('should fail if the length between the offset and end of the byte array is too short to hold the length of a nested byte array', async () => {
- const emptyByteArray = ethUtil.bufferToHex(new Buffer(shortTestBytesAsBuffer.byteLength));
- const badOffset = new BigNumber(ethUtil.toBuffer(shortTestBytesAsBuffer).byteLength);
- return expectContractCallFailedAsync(
- libBytes.publicWriteBytesWithLength.callAsync(emptyByteArray, badOffset, shortData),
- RevertReason.LibBytesGreaterOrEqualToNestedBytesLengthRequired,
- );
- });
- });
-
- describe('memCopy', () => {
- // Create memory 0x000102...FF
- const memSize = 256;
- // tslint:disable:no-shadowed-variable
- const memory = new Uint8Array(memSize).map((_, i) => i);
- const memHex = toHex(memory);
-
- // Reference implementation to test against
- const refMemcpy = (mem: Uint8Array, dest: number, source: number, length: number): Uint8Array =>
- Uint8Array.from(mem).copyWithin(dest, source, source + length);
-
- // Test vectors: destination, source, length, job description
- type Tests = Array<[number, number, number, string]>;
-
- const test = (tests: Tests) =>
- tests.forEach(([dest, source, length, job]) =>
- it(job, async () => {
- const expected = refMemcpy(memory, dest, source, length);
- const resultStr = await libBytes.testMemcpy.callAsync(
- memHex,
- new BigNumber(dest),
- new BigNumber(source),
- new BigNumber(length),
- );
- const result = fromHex(resultStr);
- expect(result).to.deep.equal(expected);
- }),
- );
-
- test([[0, 0, 0, 'copies zero bytes with overlap']]);
-
- describe('copies forward', () =>
- test([
- [128, 0, 0, 'zero bytes'],
- [128, 0, 1, 'one byte'],
- [128, 0, 11, 'eleven bytes'],
- [128, 0, 31, 'thirty-one bytes'],
- [128, 0, 32, 'one word'],
- [128, 0, 64, 'two words'],
- [128, 0, 96, 'three words'],
- [128, 0, 33, 'one word and one byte'],
- [128, 0, 72, 'two words and eight bytes'],
- [128, 0, 100, 'three words and four bytes'],
- ]));
-
- describe('copies forward within one word', () =>
- test([
- [16, 0, 0, 'zero bytes'],
- [16, 0, 1, 'one byte'],
- [16, 0, 11, 'eleven bytes'],
- [16, 0, 16, 'sixteen bytes'],
- ]));
-
- describe('copies forward with one byte overlap', () =>
- test([
- [0, 0, 1, 'one byte'],
- [10, 0, 11, 'eleven bytes'],
- [30, 0, 31, 'thirty-one bytes'],
- [31, 0, 32, 'one word'],
- [32, 0, 33, 'one word and one byte'],
- [71, 0, 72, 'two words and eight bytes'],
- [99, 0, 100, 'three words and four bytes'],
- ]));
-
- describe('copies forward with thirty-one bytes overlap', () =>
- test([
- [0, 0, 31, 'thirty-one bytes'],
- [1, 0, 32, 'one word'],
- [2, 0, 33, 'one word and one byte'],
- [41, 0, 72, 'two words and eight bytes'],
- [69, 0, 100, 'three words and four bytes'],
- ]));
-
- describe('copies forward with one word overlap', () =>
- test([
- [0, 0, 32, 'one word'],
- [1, 0, 33, 'one word and one byte'],
- [41, 0, 72, 'two words and eight bytes'],
- [69, 0, 100, 'three words and four bytes'],
- ]));
-
- describe('copies forward with one word and one byte overlap', () =>
- test([
- [0, 0, 33, 'one word and one byte'],
- [40, 0, 72, 'two words and eight bytes'],
- [68, 0, 100, 'three words and four bytes'],
- ]));
-
- describe('copies forward with two words overlap', () =>
- test([
- [0, 0, 64, 'two words'],
- [8, 0, 72, 'two words and eight bytes'],
- [36, 0, 100, 'three words and four bytes'],
- ]));
-
- describe('copies forward within one word and one byte overlap', () =>
- test([[0, 0, 1, 'one byte'], [10, 0, 11, 'eleven bytes'], [15, 0, 16, 'sixteen bytes']]));
-
- describe('copies backward', () =>
- test([
- [0, 128, 0, 'zero bytes'],
- [0, 128, 1, 'one byte'],
- [0, 128, 11, 'eleven bytes'],
- [0, 128, 31, 'thirty-one bytes'],
- [0, 128, 32, 'one word'],
- [0, 128, 64, 'two words'],
- [0, 128, 96, 'three words'],
- [0, 128, 33, 'one word and one byte'],
- [0, 128, 72, 'two words and eight bytes'],
- [0, 128, 100, 'three words and four bytes'],
- ]));
-
- describe('copies backward within one word', () =>
- test([
- [0, 16, 0, 'zero bytes'],
- [0, 16, 1, 'one byte'],
- [0, 16, 11, 'eleven bytes'],
- [0, 16, 16, 'sixteen bytes'],
- ]));
-
- describe('copies backward with one byte overlap', () =>
- test([
- [0, 0, 1, 'one byte'],
- [0, 10, 11, 'eleven bytes'],
- [0, 30, 31, 'thirty-one bytes'],
- [0, 31, 32, 'one word'],
- [0, 32, 33, 'one word and one byte'],
- [0, 71, 72, 'two words and eight bytes'],
- [0, 99, 100, 'three words and four bytes'],
- ]));
-
- describe('copies backward with thirty-one bytes overlap', () =>
- test([
- [0, 0, 31, 'thirty-one bytes'],
- [0, 1, 32, 'one word'],
- [0, 2, 33, 'one word and one byte'],
- [0, 41, 72, 'two words and eight bytes'],
- [0, 69, 100, 'three words and four bytes'],
- ]));
-
- describe('copies backward with one word overlap', () =>
- test([
- [0, 0, 32, 'one word'],
- [0, 1, 33, 'one word and one byte'],
- [0, 41, 72, 'two words and eight bytes'],
- [0, 69, 100, 'three words and four bytes'],
- ]));
-
- describe('copies backward with one word and one byte overlap', () =>
- test([
- [0, 0, 33, 'one word and one byte'],
- [0, 40, 72, 'two words and eight bytes'],
- [0, 68, 100, 'three words and four bytes'],
- ]));
-
- describe('copies backward with two words overlap', () =>
- test([
- [0, 0, 64, 'two words'],
- [0, 8, 72, 'two words and eight bytes'],
- [0, 36, 100, 'three words and four bytes'],
- ]));
-
- describe('copies forward within one word and one byte overlap', () =>
- test([[0, 0, 1, 'one byte'], [0, 10, 11, 'eleven bytes'], [0, 15, 16, 'sixteen bytes']]));
- });
-});
-// tslint:disable:max-file-line-count
diff --git a/packages/contracts/test/multisig/asset_proxy_owner.ts b/packages/contracts/test/multisig/asset_proxy_owner.ts
deleted file mode 100644
index 087152316..000000000
--- a/packages/contracts/test/multisig/asset_proxy_owner.ts
+++ /dev/null
@@ -1,498 +0,0 @@
-import { BlockchainLifecycle } from '@0x/dev-utils';
-import { RevertReason } from '@0x/types';
-import { BigNumber } from '@0x/utils';
-import * as chai from 'chai';
-import { LogWithDecodedArgs } from 'ethereum-types';
-
-import {
- AssetProxyOwnerAssetProxyRegistrationEventArgs,
- AssetProxyOwnerContract,
- AssetProxyOwnerExecutionEventArgs,
- AssetProxyOwnerExecutionFailureEventArgs,
- AssetProxyOwnerSubmissionEventArgs,
-} from '../../generated-wrappers/asset_proxy_owner';
-import { MixinAuthorizableContract } from '../../generated-wrappers/mixin_authorizable';
-import { TestAssetProxyOwnerContract } from '../../generated-wrappers/test_asset_proxy_owner';
-import { artifacts } from '../../src/artifacts';
-import {
- expectContractCallFailedAsync,
- expectContractCreationFailedAsync,
- expectTransactionFailedAsync,
- expectTransactionFailedWithoutReasonAsync,
- sendTransactionResult,
-} from '../utils/assertions';
-import { increaseTimeAndMineBlockAsync } from '../utils/block_timestamp';
-import { chaiSetup } from '../utils/chai_setup';
-import { constants } from '../utils/constants';
-import { MultiSigWrapper } from '../utils/multi_sig_wrapper';
-import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper';
-
-chaiSetup.configure();
-const expect = chai.expect;
-const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
-// tslint:disable:no-unnecessary-type-assertion
-describe('AssetProxyOwner', () => {
- let owners: string[];
- let authorized: string;
- let notOwner: string;
- const REQUIRED_APPROVALS = new BigNumber(2);
- const SECONDS_TIME_LOCKED = new BigNumber(1000000);
-
- let erc20Proxy: MixinAuthorizableContract;
- let erc721Proxy: MixinAuthorizableContract;
- let testAssetProxyOwner: TestAssetProxyOwnerContract;
- let multiSigWrapper: MultiSigWrapper;
-
- before(async () => {
- await blockchainLifecycle.startAsync();
- });
- after(async () => {
- await blockchainLifecycle.revertAsync();
- });
- before(async () => {
- const accounts = await web3Wrapper.getAvailableAddressesAsync();
- owners = [accounts[0], accounts[1]];
- authorized = accounts[2];
- notOwner = accounts[3];
- const initialOwner = accounts[0];
- erc20Proxy = await MixinAuthorizableContract.deployFrom0xArtifactAsync(
- artifacts.MixinAuthorizable,
- provider,
- txDefaults,
- );
- erc721Proxy = await MixinAuthorizableContract.deployFrom0xArtifactAsync(
- artifacts.MixinAuthorizable,
- provider,
- txDefaults,
- );
- const defaultAssetProxyContractAddresses: string[] = [];
- testAssetProxyOwner = await TestAssetProxyOwnerContract.deployFrom0xArtifactAsync(
- artifacts.TestAssetProxyOwner,
- provider,
- txDefaults,
- owners,
- defaultAssetProxyContractAddresses,
- REQUIRED_APPROVALS,
- SECONDS_TIME_LOCKED,
- );
- multiSigWrapper = new MultiSigWrapper(testAssetProxyOwner, provider);
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc20Proxy.transferOwnership.sendTransactionAsync(testAssetProxyOwner.address, {
- from: initialOwner,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc721Proxy.transferOwnership.sendTransactionAsync(testAssetProxyOwner.address, {
- from: initialOwner,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- });
- beforeEach(async () => {
- await blockchainLifecycle.startAsync();
- });
- afterEach(async () => {
- await blockchainLifecycle.revertAsync();
- });
-
- describe('constructor', () => {
- it('should register passed in assetProxyContracts', async () => {
- const assetProxyContractAddresses = [erc20Proxy.address, erc721Proxy.address];
- const newMultiSig = await AssetProxyOwnerContract.deployFrom0xArtifactAsync(
- artifacts.AssetProxyOwner,
- provider,
- txDefaults,
- owners,
- assetProxyContractAddresses,
- REQUIRED_APPROVALS,
- SECONDS_TIME_LOCKED,
- );
- const isErc20ProxyRegistered = await newMultiSig.isAssetProxyRegistered.callAsync(erc20Proxy.address);
- const isErc721ProxyRegistered = await newMultiSig.isAssetProxyRegistered.callAsync(erc721Proxy.address);
- expect(isErc20ProxyRegistered).to.equal(true);
- expect(isErc721ProxyRegistered).to.equal(true);
- });
- it('should throw if a null address is included in assetProxyContracts', async () => {
- const assetProxyContractAddresses = [erc20Proxy.address, constants.NULL_ADDRESS];
- return expectContractCreationFailedAsync(
- (AssetProxyOwnerContract.deployFrom0xArtifactAsync(
- artifacts.AssetProxyOwner,
- provider,
- txDefaults,
- owners,
- assetProxyContractAddresses,
- REQUIRED_APPROVALS,
- SECONDS_TIME_LOCKED,
- ) as any) as sendTransactionResult,
- RevertReason.InvalidAssetProxy,
- );
- });
- });
-
- describe('isFunctionRemoveAuthorizedAddressAtIndex', () => {
- it('should return false if data is not for removeAuthorizedAddressAtIndex', async () => {
- const notRemoveAuthorizedAddressData = erc20Proxy.addAuthorizedAddress.getABIEncodedTransactionData(
- owners[0],
- );
-
- const isFunctionRemoveAuthorizedAddressAtIndex = await testAssetProxyOwner.isFunctionRemoveAuthorizedAddressAtIndex.callAsync(
- notRemoveAuthorizedAddressData,
- );
- expect(isFunctionRemoveAuthorizedAddressAtIndex).to.be.false();
- });
-
- it('should return true if data is for removeAuthorizedAddressAtIndex', async () => {
- const index = new BigNumber(0);
- const removeAuthorizedAddressAtIndexData = erc20Proxy.removeAuthorizedAddressAtIndex.getABIEncodedTransactionData(
- owners[0],
- index,
- );
- const isFunctionRemoveAuthorizedAddressAtIndex = await testAssetProxyOwner.isFunctionRemoveAuthorizedAddressAtIndex.callAsync(
- removeAuthorizedAddressAtIndexData,
- );
- expect(isFunctionRemoveAuthorizedAddressAtIndex).to.be.true();
- });
- });
-
- describe('registerAssetProxy', () => {
- it('should throw if not called by multisig', async () => {
- const isRegistered = true;
- return expectTransactionFailedWithoutReasonAsync(
- testAssetProxyOwner.registerAssetProxy.sendTransactionAsync(erc20Proxy.address, isRegistered, {
- from: owners[0],
- }),
- );
- });
-
- it('should register an address if called by multisig after timelock', async () => {
- const addressToRegister = erc20Proxy.address;
- const isRegistered = true;
- const registerAssetProxyData = testAssetProxyOwner.registerAssetProxy.getABIEncodedTransactionData(
- addressToRegister,
- isRegistered,
- );
- const submitTxRes = await multiSigWrapper.submitTransactionAsync(
- testAssetProxyOwner.address,
- registerAssetProxyData,
- owners[0],
- );
-
- const log = submitTxRes.logs[0] as LogWithDecodedArgs<AssetProxyOwnerSubmissionEventArgs>;
- const txId = log.args.transactionId;
-
- await multiSigWrapper.confirmTransactionAsync(txId, owners[1]);
- await increaseTimeAndMineBlockAsync(SECONDS_TIME_LOCKED.toNumber());
-
- const executeTxRes = await multiSigWrapper.executeTransactionAsync(txId, owners[0]);
- const registerLog = executeTxRes.logs[0] as LogWithDecodedArgs<
- AssetProxyOwnerAssetProxyRegistrationEventArgs
- >;
- expect(registerLog.args.assetProxyContract).to.equal(addressToRegister);
- expect(registerLog.args.isRegistered).to.equal(isRegistered);
-
- const isAssetProxyRegistered = await testAssetProxyOwner.isAssetProxyRegistered.callAsync(
- addressToRegister,
- );
- expect(isAssetProxyRegistered).to.equal(isRegistered);
- });
-
- it('should fail if registering a null address', async () => {
- const addressToRegister = constants.NULL_ADDRESS;
- const isRegistered = true;
- const registerAssetProxyData = testAssetProxyOwner.registerAssetProxy.getABIEncodedTransactionData(
- addressToRegister,
- isRegistered,
- );
- const submitTxRes = await multiSigWrapper.submitTransactionAsync(
- testAssetProxyOwner.address,
- registerAssetProxyData,
- owners[0],
- );
- const log = submitTxRes.logs[0] as LogWithDecodedArgs<AssetProxyOwnerSubmissionEventArgs>;
- const txId = log.args.transactionId;
-
- await multiSigWrapper.confirmTransactionAsync(txId, owners[1]);
- await increaseTimeAndMineBlockAsync(SECONDS_TIME_LOCKED.toNumber());
-
- const executeTxRes = await multiSigWrapper.executeTransactionAsync(txId, owners[0]);
- const failureLog = executeTxRes.logs[0] as LogWithDecodedArgs<AssetProxyOwnerExecutionFailureEventArgs>;
- expect(failureLog.args.transactionId).to.be.bignumber.equal(txId);
-
- const isAssetProxyRegistered = await testAssetProxyOwner.isAssetProxyRegistered.callAsync(
- addressToRegister,
- );
- expect(isAssetProxyRegistered).to.equal(false);
- });
- });
-
- describe('Calling removeAuthorizedAddressAtIndex', () => {
- const erc20Index = new BigNumber(0);
- const erc721Index = new BigNumber(1);
- before('authorize both proxies and register erc20 proxy', async () => {
- // Only register ERC20 proxy
- const addressToRegister = erc20Proxy.address;
- const isRegistered = true;
- const registerAssetProxyData = testAssetProxyOwner.registerAssetProxy.getABIEncodedTransactionData(
- addressToRegister,
- isRegistered,
- );
- const registerAssetProxySubmitRes = await multiSigWrapper.submitTransactionAsync(
- testAssetProxyOwner.address,
- registerAssetProxyData,
- owners[0],
- );
- const registerAssetProxySubmitLog = registerAssetProxySubmitRes.logs[0] as LogWithDecodedArgs<
- AssetProxyOwnerSubmissionEventArgs
- >;
-
- const addAuthorizedAddressData = erc20Proxy.addAuthorizedAddress.getABIEncodedTransactionData(authorized);
- const erc20AddAuthorizedAddressSubmitRes = await multiSigWrapper.submitTransactionAsync(
- erc20Proxy.address,
- addAuthorizedAddressData,
- owners[0],
- );
- const erc721AddAuthorizedAddressSubmitRes = await multiSigWrapper.submitTransactionAsync(
- erc721Proxy.address,
- addAuthorizedAddressData,
- owners[0],
- );
- const erc20AddAuthorizedAddressSubmitLog = erc20AddAuthorizedAddressSubmitRes.logs[0] as LogWithDecodedArgs<
- AssetProxyOwnerSubmissionEventArgs
- >;
- const erc721AddAuthorizedAddressSubmitLog = erc721AddAuthorizedAddressSubmitRes
- .logs[0] as LogWithDecodedArgs<AssetProxyOwnerSubmissionEventArgs>;
-
- const registerAssetProxyTxId = registerAssetProxySubmitLog.args.transactionId;
- const erc20AddAuthorizedAddressTxId = erc20AddAuthorizedAddressSubmitLog.args.transactionId;
- const erc721AddAuthorizedAddressTxId = erc721AddAuthorizedAddressSubmitLog.args.transactionId;
-
- await multiSigWrapper.confirmTransactionAsync(registerAssetProxyTxId, owners[1]);
- await multiSigWrapper.confirmTransactionAsync(erc20AddAuthorizedAddressTxId, owners[1]);
- await multiSigWrapper.confirmTransactionAsync(erc721AddAuthorizedAddressTxId, owners[1]);
- await increaseTimeAndMineBlockAsync(SECONDS_TIME_LOCKED.toNumber());
- await multiSigWrapper.executeTransactionAsync(registerAssetProxyTxId, owners[0]);
- await multiSigWrapper.executeTransactionAsync(erc20AddAuthorizedAddressTxId, owners[0], {
- gas: constants.MAX_EXECUTE_TRANSACTION_GAS,
- });
- await multiSigWrapper.executeTransactionAsync(erc721AddAuthorizedAddressTxId, owners[0], {
- gas: constants.MAX_EXECUTE_TRANSACTION_GAS,
- });
- });
-
- describe('validRemoveAuthorizedAddressAtIndexTx', () => {
- it('should revert if data is not for removeAuthorizedAddressAtIndex and proxy is registered', async () => {
- const notRemoveAuthorizedAddressData = erc20Proxy.addAuthorizedAddress.getABIEncodedTransactionData(
- authorized,
- );
- const submitTxRes = await multiSigWrapper.submitTransactionAsync(
- erc20Proxy.address,
- notRemoveAuthorizedAddressData,
- owners[0],
- );
- const log = submitTxRes.logs[0] as LogWithDecodedArgs<AssetProxyOwnerSubmissionEventArgs>;
- const txId = log.args.transactionId;
- return expectContractCallFailedAsync(
- testAssetProxyOwner.testValidRemoveAuthorizedAddressAtIndexTx.callAsync(txId),
- RevertReason.InvalidFunctionSelector,
- );
- });
-
- it('should return true if data is for removeAuthorizedAddressAtIndex and proxy is registered', async () => {
- const removeAuthorizedAddressAtIndexData = erc20Proxy.removeAuthorizedAddressAtIndex.getABIEncodedTransactionData(
- authorized,
- erc20Index,
- );
- const submitTxRes = await multiSigWrapper.submitTransactionAsync(
- erc20Proxy.address,
- removeAuthorizedAddressAtIndexData,
- owners[0],
- );
- const log = submitTxRes.logs[0] as LogWithDecodedArgs<AssetProxyOwnerSubmissionEventArgs>;
- const txId = log.args.transactionId;
- const isValidRemoveAuthorizedAddressAtIndexTx = await testAssetProxyOwner.testValidRemoveAuthorizedAddressAtIndexTx.callAsync(
- txId,
- );
- expect(isValidRemoveAuthorizedAddressAtIndexTx).to.be.true();
- });
-
- it('should revert if data is for removeAuthorizedAddressAtIndex and proxy is not registered', async () => {
- const removeAuthorizedAddressAtIndexData = erc721Proxy.removeAuthorizedAddressAtIndex.getABIEncodedTransactionData(
- authorized,
- erc721Index,
- );
- const submitTxRes = await multiSigWrapper.submitTransactionAsync(
- erc721Proxy.address,
- removeAuthorizedAddressAtIndexData,
- owners[0],
- );
- const log = submitTxRes.logs[0] as LogWithDecodedArgs<AssetProxyOwnerSubmissionEventArgs>;
- const txId = log.args.transactionId;
- return expectContractCallFailedAsync(
- testAssetProxyOwner.testValidRemoveAuthorizedAddressAtIndexTx.callAsync(txId),
- RevertReason.UnregisteredAssetProxy,
- );
- });
- });
-
- describe('executeRemoveAuthorizedAddressAtIndex', () => {
- it('should throw without the required confirmations', async () => {
- const removeAuthorizedAddressAtIndexData = erc20Proxy.removeAuthorizedAddressAtIndex.getABIEncodedTransactionData(
- authorized,
- erc20Index,
- );
- const res = await multiSigWrapper.submitTransactionAsync(
- erc20Proxy.address,
- removeAuthorizedAddressAtIndexData,
- owners[0],
- );
- const log = res.logs[0] as LogWithDecodedArgs<AssetProxyOwnerSubmissionEventArgs>;
- const txId = log.args.transactionId;
-
- return expectTransactionFailedAsync(
- testAssetProxyOwner.executeRemoveAuthorizedAddressAtIndex.sendTransactionAsync(txId, {
- from: owners[1],
- }),
- RevertReason.TxNotFullyConfirmed,
- );
- });
-
- it('should throw if tx destination is not registered', async () => {
- const removeAuthorizedAddressAtIndexData = erc721Proxy.removeAuthorizedAddressAtIndex.getABIEncodedTransactionData(
- authorized,
- erc721Index,
- );
- const res = await multiSigWrapper.submitTransactionAsync(
- erc721Proxy.address,
- removeAuthorizedAddressAtIndexData,
- owners[0],
- );
- const log = res.logs[0] as LogWithDecodedArgs<AssetProxyOwnerSubmissionEventArgs>;
- const txId = log.args.transactionId;
-
- await multiSigWrapper.confirmTransactionAsync(txId, owners[1]);
-
- return expectTransactionFailedAsync(
- testAssetProxyOwner.executeRemoveAuthorizedAddressAtIndex.sendTransactionAsync(txId, {
- from: owners[1],
- }),
- RevertReason.UnregisteredAssetProxy,
- );
- });
-
- it('should throw if tx data is not for removeAuthorizedAddressAtIndex', async () => {
- const newAuthorized = owners[1];
- const addAuthorizedAddressData = erc20Proxy.addAuthorizedAddress.getABIEncodedTransactionData(
- newAuthorized,
- );
- const res = await multiSigWrapper.submitTransactionAsync(
- erc20Proxy.address,
- addAuthorizedAddressData,
- owners[0],
- );
- const log = res.logs[0] as LogWithDecodedArgs<AssetProxyOwnerSubmissionEventArgs>;
- const txId = log.args.transactionId;
-
- await multiSigWrapper.confirmTransactionAsync(txId, owners[1]);
-
- return expectTransactionFailedAsync(
- testAssetProxyOwner.executeRemoveAuthorizedAddressAtIndex.sendTransactionAsync(txId, {
- from: owners[1],
- }),
- RevertReason.InvalidFunctionSelector,
- );
- });
-
- it('should execute removeAuthorizedAddressAtIndex for registered address if fully confirmed and called by owner', async () => {
- const isAuthorizedBefore = await erc20Proxy.authorized.callAsync(authorized);
- expect(isAuthorizedBefore).to.equal(true);
-
- const removeAuthorizedAddressAtIndexData = erc20Proxy.removeAuthorizedAddressAtIndex.getABIEncodedTransactionData(
- authorized,
- erc20Index,
- );
- const submitRes = await multiSigWrapper.submitTransactionAsync(
- erc20Proxy.address,
- removeAuthorizedAddressAtIndexData,
- owners[0],
- );
- const submitLog = submitRes.logs[0] as LogWithDecodedArgs<AssetProxyOwnerSubmissionEventArgs>;
- const txId = submitLog.args.transactionId;
-
- await multiSigWrapper.confirmTransactionAsync(txId, owners[1]);
-
- const execRes = await multiSigWrapper.executeRemoveAuthorizedAddressAtIndexAsync(txId, owners[0]);
- const execLog = execRes.logs[1] as LogWithDecodedArgs<AssetProxyOwnerExecutionEventArgs>;
- expect(execLog.args.transactionId).to.be.bignumber.equal(txId);
-
- const tx = await testAssetProxyOwner.transactions.callAsync(txId);
- const isExecuted = tx[3];
- expect(isExecuted).to.equal(true);
-
- const isAuthorizedAfter = await erc20Proxy.authorized.callAsync(authorized);
- expect(isAuthorizedAfter).to.equal(false);
- });
-
- it('should execute removeAuthorizedAddressAtIndex for registered address if fully confirmed and called by non-owner', async () => {
- const isAuthorizedBefore = await erc20Proxy.authorized.callAsync(authorized);
- expect(isAuthorizedBefore).to.equal(true);
-
- const removeAuthorizedAddressAtIndexData = erc20Proxy.removeAuthorizedAddressAtIndex.getABIEncodedTransactionData(
- authorized,
- erc20Index,
- );
- const submitRes = await multiSigWrapper.submitTransactionAsync(
- erc20Proxy.address,
- removeAuthorizedAddressAtIndexData,
- owners[0],
- );
- const submitLog = submitRes.logs[0] as LogWithDecodedArgs<AssetProxyOwnerSubmissionEventArgs>;
- const txId = submitLog.args.transactionId;
-
- await multiSigWrapper.confirmTransactionAsync(txId, owners[1]);
-
- const execRes = await multiSigWrapper.executeRemoveAuthorizedAddressAtIndexAsync(txId, notOwner);
- const execLog = execRes.logs[1] as LogWithDecodedArgs<AssetProxyOwnerExecutionEventArgs>;
- expect(execLog.args.transactionId).to.be.bignumber.equal(txId);
-
- const tx = await testAssetProxyOwner.transactions.callAsync(txId);
- const isExecuted = tx[3];
- expect(isExecuted).to.equal(true);
-
- const isAuthorizedAfter = await erc20Proxy.authorized.callAsync(authorized);
- expect(isAuthorizedAfter).to.equal(false);
- });
-
- it('should throw if already executed', async () => {
- const removeAuthorizedAddressAtIndexData = erc20Proxy.removeAuthorizedAddressAtIndex.getABIEncodedTransactionData(
- authorized,
- erc20Index,
- );
- const submitRes = await multiSigWrapper.submitTransactionAsync(
- erc20Proxy.address,
- removeAuthorizedAddressAtIndexData,
- owners[0],
- );
- const submitLog = submitRes.logs[0] as LogWithDecodedArgs<AssetProxyOwnerSubmissionEventArgs>;
- const txId = submitLog.args.transactionId;
-
- await multiSigWrapper.confirmTransactionAsync(txId, owners[1]);
-
- const execRes = await multiSigWrapper.executeRemoveAuthorizedAddressAtIndexAsync(txId, owners[0]);
- const execLog = execRes.logs[1] as LogWithDecodedArgs<AssetProxyOwnerExecutionEventArgs>;
- expect(execLog.args.transactionId).to.be.bignumber.equal(txId);
-
- const tx = await testAssetProxyOwner.transactions.callAsync(txId);
- const isExecuted = tx[3];
- expect(isExecuted).to.equal(true);
-
- return expectTransactionFailedWithoutReasonAsync(
- testAssetProxyOwner.executeRemoveAuthorizedAddressAtIndex.sendTransactionAsync(txId, {
- from: owners[1],
- }),
- );
- });
- });
- });
-});
-// tslint:enable:no-unnecessary-type-assertion
diff --git a/packages/contracts/test/multisig/multi_sig_with_time_lock.ts b/packages/contracts/test/multisig/multi_sig_with_time_lock.ts
deleted file mode 100644
index 1c0cb0515..000000000
--- a/packages/contracts/test/multisig/multi_sig_with_time_lock.ts
+++ /dev/null
@@ -1,347 +0,0 @@
-import { BlockchainLifecycle } from '@0x/dev-utils';
-import { RevertReason } from '@0x/types';
-import { BigNumber } from '@0x/utils';
-import * as chai from 'chai';
-import { LogWithDecodedArgs } from 'ethereum-types';
-import * as _ from 'lodash';
-
-import { DummyERC20TokenContract } from '../../generated-wrappers/dummy_erc20_token';
-import {
- MultiSigWalletWithTimeLockConfirmationEventArgs,
- MultiSigWalletWithTimeLockConfirmationTimeSetEventArgs,
- MultiSigWalletWithTimeLockContract,
- MultiSigWalletWithTimeLockExecutionEventArgs,
- MultiSigWalletWithTimeLockExecutionFailureEventArgs,
- MultiSigWalletWithTimeLockSubmissionEventArgs,
-} from '../../generated-wrappers/multi_sig_wallet_with_time_lock';
-import { artifacts } from '../../src/artifacts';
-import { expectTransactionFailedAsync, expectTransactionFailedWithoutReasonAsync } from '../utils/assertions';
-import { increaseTimeAndMineBlockAsync } from '../utils/block_timestamp';
-import { chaiSetup } from '../utils/chai_setup';
-import { constants } from '../utils/constants';
-import { MultiSigWrapper } from '../utils/multi_sig_wrapper';
-import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper';
-
-chaiSetup.configure();
-const expect = chai.expect;
-const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
-// tslint:disable:no-unnecessary-type-assertion
-describe('MultiSigWalletWithTimeLock', () => {
- let owners: string[];
- let notOwner: string;
- const REQUIRED_APPROVALS = new BigNumber(2);
- const SECONDS_TIME_LOCKED = new BigNumber(1000000);
-
- before(async () => {
- await blockchainLifecycle.startAsync();
- });
- after(async () => {
- await blockchainLifecycle.revertAsync();
- });
- before(async () => {
- const accounts = await web3Wrapper.getAvailableAddressesAsync();
- owners = [accounts[0], accounts[1], accounts[2]];
- notOwner = accounts[3];
- });
-
- let multiSig: MultiSigWalletWithTimeLockContract;
- let multiSigWrapper: MultiSigWrapper;
-
- beforeEach(async () => {
- await blockchainLifecycle.startAsync();
- });
- afterEach(async () => {
- await blockchainLifecycle.revertAsync();
- });
-
- describe('external_call', () => {
- it('should be internal', async () => {
- const secondsTimeLocked = new BigNumber(0);
- multiSig = await MultiSigWalletWithTimeLockContract.deployFrom0xArtifactAsync(
- artifacts.MultiSigWalletWithTimeLock,
- provider,
- txDefaults,
- owners,
- REQUIRED_APPROVALS,
- secondsTimeLocked,
- );
- expect(_.isUndefined((multiSig as any).external_call)).to.be.equal(true);
- });
- });
- describe('confirmTransaction', () => {
- let txId: BigNumber;
- beforeEach(async () => {
- const secondsTimeLocked = new BigNumber(0);
- multiSig = await MultiSigWalletWithTimeLockContract.deployFrom0xArtifactAsync(
- artifacts.MultiSigWalletWithTimeLock,
- provider,
- txDefaults,
- owners,
- REQUIRED_APPROVALS,
- secondsTimeLocked,
- );
- multiSigWrapper = new MultiSigWrapper(multiSig, provider);
- const destination = notOwner;
- const data = constants.NULL_BYTES;
- const txReceipt = await multiSigWrapper.submitTransactionAsync(destination, data, owners[0]);
- txId = (txReceipt.logs[0] as LogWithDecodedArgs<MultiSigWalletWithTimeLockSubmissionEventArgs>).args
- .transactionId;
- });
- it('should revert if called by a non-owner', async () => {
- await expectTransactionFailedWithoutReasonAsync(multiSigWrapper.confirmTransactionAsync(txId, notOwner));
- });
- it('should revert if transaction does not exist', async () => {
- const nonexistentTxId = new BigNumber(123456789);
- await expectTransactionFailedWithoutReasonAsync(
- multiSigWrapper.confirmTransactionAsync(nonexistentTxId, owners[1]),
- );
- });
- it('should revert if transaction is already confirmed by caller', async () => {
- await expectTransactionFailedWithoutReasonAsync(multiSigWrapper.confirmTransactionAsync(txId, owners[0]));
- });
- it('should confirm transaction for caller and log a Confirmation event', async () => {
- const txReceipt = await multiSigWrapper.confirmTransactionAsync(txId, owners[1]);
- const log = txReceipt.logs[0] as LogWithDecodedArgs<MultiSigWalletWithTimeLockConfirmationEventArgs>;
- expect(log.event).to.be.equal('Confirmation');
- expect(log.args.sender).to.be.equal(owners[1]);
- expect(log.args.transactionId).to.be.bignumber.equal(txId);
- });
- it('should revert if fully confirmed', async () => {
- await multiSigWrapper.confirmTransactionAsync(txId, owners[1]);
- await expectTransactionFailedAsync(
- multiSigWrapper.confirmTransactionAsync(txId, owners[2]),
- RevertReason.TxFullyConfirmed,
- );
- });
- it('should set the confirmation time of the transaction if it becomes fully confirmed', async () => {
- const txReceipt = await multiSigWrapper.confirmTransactionAsync(txId, owners[1]);
- const blockNum = await web3Wrapper.getBlockNumberAsync();
- const timestamp = new BigNumber(await web3Wrapper.getBlockTimestampAsync(blockNum));
- const log = txReceipt.logs[1] as LogWithDecodedArgs<MultiSigWalletWithTimeLockConfirmationTimeSetEventArgs>;
- expect(log.args.confirmationTime).to.be.bignumber.equal(timestamp);
- expect(log.args.transactionId).to.be.bignumber.equal(txId);
- });
- });
- describe('executeTransaction', () => {
- let txId: BigNumber;
- const secondsTimeLocked = new BigNumber(1000000);
- beforeEach(async () => {
- multiSig = await MultiSigWalletWithTimeLockContract.deployFrom0xArtifactAsync(
- artifacts.MultiSigWalletWithTimeLock,
- provider,
- txDefaults,
- owners,
- REQUIRED_APPROVALS,
- secondsTimeLocked,
- );
- multiSigWrapper = new MultiSigWrapper(multiSig, provider);
- const destination = notOwner;
- const data = constants.NULL_BYTES;
- const txReceipt = await multiSigWrapper.submitTransactionAsync(destination, data, owners[0]);
- txId = (txReceipt.logs[0] as LogWithDecodedArgs<MultiSigWalletWithTimeLockSubmissionEventArgs>).args
- .transactionId;
- });
- it('should revert if transaction has not been fully confirmed', async () => {
- await increaseTimeAndMineBlockAsync(secondsTimeLocked.toNumber());
- await expectTransactionFailedAsync(
- multiSigWrapper.executeTransactionAsync(txId, owners[1]),
- RevertReason.TxNotFullyConfirmed,
- );
- });
- it('should revert if time lock has not passed', async () => {
- await multiSigWrapper.confirmTransactionAsync(txId, owners[1]);
- await expectTransactionFailedAsync(
- multiSigWrapper.executeTransactionAsync(txId, owners[1]),
- RevertReason.TimeLockIncomplete,
- );
- });
- it('should execute a transaction and log an Execution event if successful and called by owner', async () => {
- await multiSigWrapper.confirmTransactionAsync(txId, owners[1]);
- await increaseTimeAndMineBlockAsync(secondsTimeLocked.toNumber());
- const txReceipt = await multiSigWrapper.executeTransactionAsync(txId, owners[1]);
- const log = txReceipt.logs[0] as LogWithDecodedArgs<MultiSigWalletWithTimeLockExecutionEventArgs>;
- expect(log.event).to.be.equal('Execution');
- expect(log.args.transactionId).to.be.bignumber.equal(txId);
- });
- it('should execute a transaction and log an Execution event if successful and called by non-owner', async () => {
- await multiSigWrapper.confirmTransactionAsync(txId, owners[1]);
- await increaseTimeAndMineBlockAsync(secondsTimeLocked.toNumber());
- const txReceipt = await multiSigWrapper.executeTransactionAsync(txId, notOwner);
- const log = txReceipt.logs[0] as LogWithDecodedArgs<MultiSigWalletWithTimeLockExecutionEventArgs>;
- expect(log.event).to.be.equal('Execution');
- expect(log.args.transactionId).to.be.bignumber.equal(txId);
- });
- it('should revert if a required confirmation is revoked before executeTransaction is called', async () => {
- await multiSigWrapper.confirmTransactionAsync(txId, owners[1]);
- await increaseTimeAndMineBlockAsync(secondsTimeLocked.toNumber());
- await multiSigWrapper.revokeConfirmationAsync(txId, owners[0]);
- await expectTransactionFailedAsync(
- multiSigWrapper.executeTransactionAsync(txId, owners[1]),
- RevertReason.TxNotFullyConfirmed,
- );
- });
- it('should revert if transaction has been executed', async () => {
- await multiSigWrapper.confirmTransactionAsync(txId, owners[1]);
- await increaseTimeAndMineBlockAsync(secondsTimeLocked.toNumber());
- const txReceipt = await multiSigWrapper.executeTransactionAsync(txId, owners[1]);
- const log = txReceipt.logs[0] as LogWithDecodedArgs<MultiSigWalletWithTimeLockExecutionEventArgs>;
- expect(log.args.transactionId).to.be.bignumber.equal(txId);
- await expectTransactionFailedWithoutReasonAsync(multiSigWrapper.executeTransactionAsync(txId, owners[1]));
- });
- it("should log an ExecutionFailure event and not update the transaction's execution state if unsuccessful", async () => {
- const contractWithoutFallback = await DummyERC20TokenContract.deployFrom0xArtifactAsync(
- artifacts.DummyERC20Token,
- provider,
- txDefaults,
- constants.DUMMY_TOKEN_NAME,
- constants.DUMMY_TOKEN_SYMBOL,
- constants.DUMMY_TOKEN_DECIMALS,
- constants.DUMMY_TOKEN_TOTAL_SUPPLY,
- );
- const data = constants.NULL_BYTES;
- const value = new BigNumber(10);
- const submissionTxReceipt = await multiSigWrapper.submitTransactionAsync(
- contractWithoutFallback.address,
- data,
- owners[0],
- { value },
- );
- const newTxId = (submissionTxReceipt.logs[0] as LogWithDecodedArgs<
- MultiSigWalletWithTimeLockSubmissionEventArgs
- >).args.transactionId;
- await multiSigWrapper.confirmTransactionAsync(newTxId, owners[1]);
- await increaseTimeAndMineBlockAsync(secondsTimeLocked.toNumber());
- const txReceipt = await multiSigWrapper.executeTransactionAsync(newTxId, owners[1]);
- const executionFailureLog = txReceipt.logs[0] as LogWithDecodedArgs<
- MultiSigWalletWithTimeLockExecutionFailureEventArgs
- >;
- expect(executionFailureLog.event).to.be.equal('ExecutionFailure');
- expect(executionFailureLog.args.transactionId).to.be.bignumber.equal(newTxId);
- });
- });
- describe('changeTimeLock', () => {
- describe('initially non-time-locked', async () => {
- before(async () => {
- await blockchainLifecycle.startAsync();
- });
- after(async () => {
- await blockchainLifecycle.revertAsync();
- });
- before('deploy a wallet', async () => {
- const secondsTimeLocked = new BigNumber(0);
- multiSig = await MultiSigWalletWithTimeLockContract.deployFrom0xArtifactAsync(
- artifacts.MultiSigWalletWithTimeLock,
- provider,
- txDefaults,
- owners,
- REQUIRED_APPROVALS,
- secondsTimeLocked,
- );
- multiSigWrapper = new MultiSigWrapper(multiSig, provider);
- });
-
- it('should throw when not called by wallet', async () => {
- return expectTransactionFailedWithoutReasonAsync(
- multiSig.changeTimeLock.sendTransactionAsync(SECONDS_TIME_LOCKED, { from: owners[0] }),
- );
- });
-
- it('should throw without enough confirmations', async () => {
- const destination = multiSig.address;
- const changeTimeLockData = multiSig.changeTimeLock.getABIEncodedTransactionData(SECONDS_TIME_LOCKED);
- const res = await multiSigWrapper.submitTransactionAsync(destination, changeTimeLockData, owners[0]);
- const log = res.logs[0] as LogWithDecodedArgs<MultiSigWalletWithTimeLockSubmissionEventArgs>;
- const txId = log.args.transactionId;
- return expectTransactionFailedAsync(
- multiSig.executeTransaction.sendTransactionAsync(txId, { from: owners[0] }),
- RevertReason.TxNotFullyConfirmed,
- );
- });
-
- it('should set confirmation time with enough confirmations', async () => {
- const destination = multiSig.address;
- const changeTimeLockData = multiSig.changeTimeLock.getABIEncodedTransactionData(SECONDS_TIME_LOCKED);
- const subRes = await multiSigWrapper.submitTransactionAsync(destination, changeTimeLockData, owners[0]);
- const subLog = subRes.logs[0] as LogWithDecodedArgs<MultiSigWalletWithTimeLockSubmissionEventArgs>;
- const txId = subLog.args.transactionId;
-
- const confirmRes = await multiSigWrapper.confirmTransactionAsync(txId, owners[1]);
- expect(confirmRes.logs).to.have.length(2);
-
- const blockNum = await web3Wrapper.getBlockNumberAsync();
- const blockInfo = await web3Wrapper.getBlockIfExistsAsync(blockNum);
- if (_.isUndefined(blockInfo)) {
- throw new Error(`Unexpectedly failed to fetch block at #${blockNum}`);
- }
- const timestamp = new BigNumber(blockInfo.timestamp);
- const confirmationTimeBigNum = new BigNumber(await multiSig.confirmationTimes.callAsync(txId));
-
- expect(timestamp).to.be.bignumber.equal(confirmationTimeBigNum);
- });
-
- it('should be executable with enough confirmations and secondsTimeLocked of 0', async () => {
- const destination = multiSig.address;
- const changeTimeLockData = multiSig.changeTimeLock.getABIEncodedTransactionData(SECONDS_TIME_LOCKED);
- const subRes = await multiSigWrapper.submitTransactionAsync(destination, changeTimeLockData, owners[0]);
- const subLog = subRes.logs[0] as LogWithDecodedArgs<MultiSigWalletWithTimeLockSubmissionEventArgs>;
- const txId = subLog.args.transactionId;
-
- await multiSigWrapper.confirmTransactionAsync(txId, owners[1]);
- await multiSigWrapper.executeTransactionAsync(txId, owners[1]);
-
- const secondsTimeLocked = new BigNumber(await multiSig.secondsTimeLocked.callAsync());
- expect(secondsTimeLocked).to.be.bignumber.equal(SECONDS_TIME_LOCKED);
- });
- });
- describe('initially time-locked', async () => {
- before(async () => {
- await blockchainLifecycle.startAsync();
- });
- after(async () => {
- await blockchainLifecycle.revertAsync();
- });
- let txId: BigNumber;
- const newSecondsTimeLocked = new BigNumber(0);
- before('deploy a wallet, submit transaction to change timelock, and confirm the transaction', async () => {
- multiSig = await MultiSigWalletWithTimeLockContract.deployFrom0xArtifactAsync(
- artifacts.MultiSigWalletWithTimeLock,
- provider,
- txDefaults,
- owners,
- REQUIRED_APPROVALS,
- SECONDS_TIME_LOCKED,
- );
- multiSigWrapper = new MultiSigWrapper(multiSig, provider);
-
- const changeTimeLockData = multiSig.changeTimeLock.getABIEncodedTransactionData(newSecondsTimeLocked);
- const res = await multiSigWrapper.submitTransactionAsync(
- multiSig.address,
- changeTimeLockData,
- owners[0],
- );
- const log = res.logs[0] as LogWithDecodedArgs<MultiSigWalletWithTimeLockSubmissionEventArgs>;
- txId = log.args.transactionId;
- await multiSigWrapper.confirmTransactionAsync(txId, owners[1]);
- });
-
- it('should throw if it has enough confirmations but is not past the time lock', async () => {
- return expectTransactionFailedAsync(
- multiSig.executeTransaction.sendTransactionAsync(txId, { from: owners[0] }),
- RevertReason.TimeLockIncomplete,
- );
- });
-
- it('should execute if it has enough confirmations and is past the time lock', async () => {
- await increaseTimeAndMineBlockAsync(SECONDS_TIME_LOCKED.toNumber());
- await web3Wrapper.awaitTransactionSuccessAsync(
- await multiSig.executeTransaction.sendTransactionAsync(txId, { from: owners[0] }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
-
- const secondsTimeLocked = new BigNumber(await multiSig.secondsTimeLocked.callAsync());
- expect(secondsTimeLocked).to.be.bignumber.equal(newSecondsTimeLocked);
- });
- });
- });
-});
-// tslint:enable:no-unnecessary-type-assertion
diff --git a/packages/contracts/test/tokens/erc721_token.ts b/packages/contracts/test/tokens/erc721_token.ts
deleted file mode 100644
index 72407748f..000000000
--- a/packages/contracts/test/tokens/erc721_token.ts
+++ /dev/null
@@ -1,279 +0,0 @@
-import { BlockchainLifecycle } from '@0x/dev-utils';
-import { RevertReason } from '@0x/types';
-import { BigNumber } from '@0x/utils';
-import * as chai from 'chai';
-import { LogWithDecodedArgs } from 'ethereum-types';
-
-import {
- DummyERC721ReceiverContract,
- DummyERC721ReceiverTokenReceivedEventArgs,
-} from '../../generated-wrappers/dummy_erc721_receiver';
-import {
- DummyERC721TokenContract,
- DummyERC721TokenTransferEventArgs,
-} from '../../generated-wrappers/dummy_erc721_token';
-import { InvalidERC721ReceiverContract } from '../../generated-wrappers/invalid_erc721_receiver';
-import { artifacts } from '../../src/artifacts';
-import { expectTransactionFailedAsync, expectTransactionFailedWithoutReasonAsync } from '../utils/assertions';
-import { chaiSetup } from '../utils/chai_setup';
-import { constants } from '../utils/constants';
-import { LogDecoder } from '../utils/log_decoder';
-import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper';
-
-chaiSetup.configure();
-const expect = chai.expect;
-const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
-// tslint:disable:no-unnecessary-type-assertion
-describe('ERC721Token', () => {
- let owner: string;
- let spender: string;
- let token: DummyERC721TokenContract;
- let erc721Receiver: DummyERC721ReceiverContract;
- let logDecoder: LogDecoder;
- const tokenId = new BigNumber(1);
- before(async () => {
- await blockchainLifecycle.startAsync();
- });
- after(async () => {
- await blockchainLifecycle.revertAsync();
- });
- before(async () => {
- const accounts = await web3Wrapper.getAvailableAddressesAsync();
- owner = accounts[0];
- spender = accounts[1];
- token = await DummyERC721TokenContract.deployFrom0xArtifactAsync(
- artifacts.DummyERC721Token,
- provider,
- txDefaults,
- constants.DUMMY_TOKEN_NAME,
- constants.DUMMY_TOKEN_SYMBOL,
- );
- erc721Receiver = await DummyERC721ReceiverContract.deployFrom0xArtifactAsync(
- artifacts.DummyERC721Receiver,
- provider,
- txDefaults,
- );
- logDecoder = new LogDecoder(web3Wrapper);
- await web3Wrapper.awaitTransactionSuccessAsync(
- await token.mint.sendTransactionAsync(owner, tokenId, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- });
- beforeEach(async () => {
- await blockchainLifecycle.startAsync();
- });
- afterEach(async () => {
- await blockchainLifecycle.revertAsync();
- });
-
- describe('transferFrom', () => {
- it('should revert if the tokenId is not owner', async () => {
- const from = owner;
- const to = erc721Receiver.address;
- const unownedTokenId = new BigNumber(2);
- await expectTransactionFailedAsync(
- token.transferFrom.sendTransactionAsync(from, to, unownedTokenId),
- RevertReason.Erc721ZeroOwner,
- );
- });
- it('should revert if transferring to a null address', async () => {
- const from = owner;
- const to = constants.NULL_ADDRESS;
- await expectTransactionFailedAsync(
- token.transferFrom.sendTransactionAsync(from, to, tokenId),
- RevertReason.Erc721ZeroToAddress,
- );
- });
- it('should revert if the from address does not own the token', async () => {
- const from = spender;
- const to = erc721Receiver.address;
- await expectTransactionFailedAsync(
- token.transferFrom.sendTransactionAsync(from, to, tokenId),
- RevertReason.Erc721OwnerMismatch,
- );
- });
- it('should revert if spender does not own the token, is not approved, and is not approved for all', async () => {
- const from = owner;
- const to = erc721Receiver.address;
- await expectTransactionFailedAsync(
- token.transferFrom.sendTransactionAsync(from, to, tokenId, { from: spender }),
- RevertReason.Erc721InvalidSpender,
- );
- });
- it('should transfer the token if called by owner', async () => {
- const from = owner;
- const to = erc721Receiver.address;
- const txReceipt = await logDecoder.getTxWithDecodedLogsAsync(
- await token.transferFrom.sendTransactionAsync(from, to, tokenId),
- );
- const newOwner = await token.ownerOf.callAsync(tokenId);
- expect(newOwner).to.be.equal(to);
- const log = txReceipt.logs[0] as LogWithDecodedArgs<DummyERC721TokenTransferEventArgs>;
- expect(log.args._from).to.be.equal(from);
- expect(log.args._to).to.be.equal(to);
- expect(log.args._tokenId).to.be.bignumber.equal(tokenId);
- });
- it('should transfer the token if spender is approved for all', async () => {
- const isApproved = true;
- await web3Wrapper.awaitTransactionSuccessAsync(
- await token.setApprovalForAll.sendTransactionAsync(spender, isApproved),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
-
- const from = owner;
- const to = erc721Receiver.address;
- const txReceipt = await logDecoder.getTxWithDecodedLogsAsync(
- await token.transferFrom.sendTransactionAsync(from, to, tokenId),
- );
- const newOwner = await token.ownerOf.callAsync(tokenId);
- expect(newOwner).to.be.equal(to);
- const log = txReceipt.logs[0] as LogWithDecodedArgs<DummyERC721TokenTransferEventArgs>;
- expect(log.args._from).to.be.equal(from);
- expect(log.args._to).to.be.equal(to);
- expect(log.args._tokenId).to.be.bignumber.equal(tokenId);
- });
- it('should transfer the token if spender is individually approved', async () => {
- await web3Wrapper.awaitTransactionSuccessAsync(
- await token.approve.sendTransactionAsync(spender, tokenId),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
-
- const from = owner;
- const to = erc721Receiver.address;
- const txReceipt = await logDecoder.getTxWithDecodedLogsAsync(
- await token.transferFrom.sendTransactionAsync(from, to, tokenId),
- );
- const newOwner = await token.ownerOf.callAsync(tokenId);
- expect(newOwner).to.be.equal(to);
-
- const approvedAddress = await token.getApproved.callAsync(tokenId);
- expect(approvedAddress).to.be.equal(constants.NULL_ADDRESS);
- const log = txReceipt.logs[0] as LogWithDecodedArgs<DummyERC721TokenTransferEventArgs>;
- expect(log.args._from).to.be.equal(from);
- expect(log.args._to).to.be.equal(to);
- expect(log.args._tokenId).to.be.bignumber.equal(tokenId);
- });
- });
- describe('safeTransferFrom without data', () => {
- it('should transfer token to a non-contract address if called by owner', async () => {
- const from = owner;
- const to = spender;
- const txReceipt = await logDecoder.getTxWithDecodedLogsAsync(
- await token.safeTransferFrom1.sendTransactionAsync(from, to, tokenId),
- );
- const newOwner = await token.ownerOf.callAsync(tokenId);
- expect(newOwner).to.be.equal(to);
- const log = txReceipt.logs[0] as LogWithDecodedArgs<DummyERC721TokenTransferEventArgs>;
- expect(log.args._from).to.be.equal(from);
- expect(log.args._to).to.be.equal(to);
- expect(log.args._tokenId).to.be.bignumber.equal(tokenId);
- });
- it('should revert if transferring to a contract address without onERC721Received', async () => {
- const contract = await DummyERC721TokenContract.deployFrom0xArtifactAsync(
- artifacts.DummyERC721Token,
- provider,
- txDefaults,
- constants.DUMMY_TOKEN_NAME,
- constants.DUMMY_TOKEN_SYMBOL,
- );
- const from = owner;
- const to = contract.address;
- await expectTransactionFailedWithoutReasonAsync(
- token.safeTransferFrom1.sendTransactionAsync(from, to, tokenId),
- );
- });
- it('should revert if onERC721Received does not return the correct value', async () => {
- const invalidErc721Receiver = await InvalidERC721ReceiverContract.deployFrom0xArtifactAsync(
- artifacts.InvalidERC721Receiver,
- provider,
- txDefaults,
- );
- const from = owner;
- const to = invalidErc721Receiver.address;
- await expectTransactionFailedAsync(
- token.safeTransferFrom1.sendTransactionAsync(from, to, tokenId),
- RevertReason.Erc721InvalidSelector,
- );
- });
- it('should transfer to contract and call onERC721Received with correct return value', async () => {
- const from = owner;
- const to = erc721Receiver.address;
- const txReceipt = await logDecoder.getTxWithDecodedLogsAsync(
- await token.safeTransferFrom1.sendTransactionAsync(from, to, tokenId),
- );
- const newOwner = await token.ownerOf.callAsync(tokenId);
- expect(newOwner).to.be.equal(to);
- const transferLog = txReceipt.logs[0] as LogWithDecodedArgs<DummyERC721TokenTransferEventArgs>;
- const receiverLog = txReceipt.logs[1] as LogWithDecodedArgs<DummyERC721ReceiverTokenReceivedEventArgs>;
- expect(transferLog.args._from).to.be.equal(from);
- expect(transferLog.args._to).to.be.equal(to);
- expect(transferLog.args._tokenId).to.be.bignumber.equal(tokenId);
- expect(receiverLog.args.operator).to.be.equal(owner);
- expect(receiverLog.args.from).to.be.equal(from);
- expect(receiverLog.args.tokenId).to.be.bignumber.equal(tokenId);
- expect(receiverLog.args.data).to.be.equal(constants.NULL_BYTES);
- });
- });
- describe('safeTransferFrom with data', () => {
- const data = '0x0102030405060708090a0b0c0d0e0f';
- it('should transfer token to a non-contract address if called by owner', async () => {
- const from = owner;
- const to = spender;
- const txReceipt = await logDecoder.getTxWithDecodedLogsAsync(
- await token.safeTransferFrom2.sendTransactionAsync(from, to, tokenId, data),
- );
- const newOwner = await token.ownerOf.callAsync(tokenId);
- expect(newOwner).to.be.equal(to);
- const log = txReceipt.logs[0] as LogWithDecodedArgs<DummyERC721TokenTransferEventArgs>;
- expect(log.args._from).to.be.equal(from);
- expect(log.args._to).to.be.equal(to);
- expect(log.args._tokenId).to.be.bignumber.equal(tokenId);
- });
- it('should revert if transferring to a contract address without onERC721Received', async () => {
- const contract = await DummyERC721TokenContract.deployFrom0xArtifactAsync(
- artifacts.DummyERC721Token,
- provider,
- txDefaults,
- constants.DUMMY_TOKEN_NAME,
- constants.DUMMY_TOKEN_SYMBOL,
- );
- const from = owner;
- const to = contract.address;
- await expectTransactionFailedWithoutReasonAsync(
- token.safeTransferFrom2.sendTransactionAsync(from, to, tokenId, data),
- );
- });
- it('should revert if onERC721Received does not return the correct value', async () => {
- const invalidErc721Receiver = await InvalidERC721ReceiverContract.deployFrom0xArtifactAsync(
- artifacts.InvalidERC721Receiver,
- provider,
- txDefaults,
- );
- const from = owner;
- const to = invalidErc721Receiver.address;
- await expectTransactionFailedAsync(
- token.safeTransferFrom2.sendTransactionAsync(from, to, tokenId, data),
- RevertReason.Erc721InvalidSelector,
- );
- });
- it('should transfer to contract and call onERC721Received with correct return value', async () => {
- const from = owner;
- const to = erc721Receiver.address;
- const txReceipt = await logDecoder.getTxWithDecodedLogsAsync(
- await token.safeTransferFrom2.sendTransactionAsync(from, to, tokenId, data),
- );
- const newOwner = await token.ownerOf.callAsync(tokenId);
- expect(newOwner).to.be.equal(to);
- const transferLog = txReceipt.logs[0] as LogWithDecodedArgs<DummyERC721TokenTransferEventArgs>;
- const receiverLog = txReceipt.logs[1] as LogWithDecodedArgs<DummyERC721ReceiverTokenReceivedEventArgs>;
- expect(transferLog.args._from).to.be.equal(from);
- expect(transferLog.args._to).to.be.equal(to);
- expect(transferLog.args._tokenId).to.be.bignumber.equal(tokenId);
- expect(receiverLog.args.operator).to.be.equal(owner);
- expect(receiverLog.args.from).to.be.equal(from);
- expect(receiverLog.args.tokenId).to.be.bignumber.equal(tokenId);
- expect(receiverLog.args.data).to.be.equal(data);
- });
- });
-});
-// tslint:enable:no-unnecessary-type-assertion
diff --git a/packages/contracts/test/tokens/unlimited_allowance_token.ts b/packages/contracts/test/tokens/unlimited_allowance_token.ts
deleted file mode 100644
index ea5a50522..000000000
--- a/packages/contracts/test/tokens/unlimited_allowance_token.ts
+++ /dev/null
@@ -1,191 +0,0 @@
-import { BlockchainLifecycle } from '@0x/dev-utils';
-import { RevertReason } from '@0x/types';
-import { BigNumber } from '@0x/utils';
-import * as chai from 'chai';
-
-import { DummyERC20TokenContract } from '../../generated-wrappers/dummy_erc20_token';
-import { artifacts } from '../../src/artifacts';
-import { expectContractCallFailedAsync } from '../utils/assertions';
-import { chaiSetup } from '../utils/chai_setup';
-import { constants } from '../utils/constants';
-import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper';
-
-chaiSetup.configure();
-const expect = chai.expect;
-const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
-
-describe('UnlimitedAllowanceToken', () => {
- let owner: string;
- let spender: string;
- const MAX_MINT_VALUE = new BigNumber(10000000000000000000000);
- let token: DummyERC20TokenContract;
-
- before(async () => {
- await blockchainLifecycle.startAsync();
- });
- after(async () => {
- await blockchainLifecycle.revertAsync();
- });
- before(async () => {
- const accounts = await web3Wrapper.getAvailableAddressesAsync();
- owner = accounts[0];
- spender = accounts[1];
- token = await DummyERC20TokenContract.deployFrom0xArtifactAsync(
- artifacts.DummyERC20Token,
- provider,
- txDefaults,
- constants.DUMMY_TOKEN_NAME,
- constants.DUMMY_TOKEN_SYMBOL,
- constants.DUMMY_TOKEN_DECIMALS,
- constants.DUMMY_TOKEN_TOTAL_SUPPLY,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await token.mint.sendTransactionAsync(MAX_MINT_VALUE, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- });
- beforeEach(async () => {
- await blockchainLifecycle.startAsync();
- });
- afterEach(async () => {
- await blockchainLifecycle.revertAsync();
- });
- describe('transfer', () => {
- it('should throw if owner has insufficient balance', async () => {
- const ownerBalance = await token.balanceOf.callAsync(owner);
- const amountToTransfer = ownerBalance.plus(1);
- return expectContractCallFailedAsync(
- token.transfer.callAsync(spender, amountToTransfer, { from: owner }),
- RevertReason.Erc20InsufficientBalance,
- );
- });
-
- it('should transfer balance from sender to receiver', async () => {
- const receiver = spender;
- const initOwnerBalance = await token.balanceOf.callAsync(owner);
- const amountToTransfer = new BigNumber(1);
- await web3Wrapper.awaitTransactionSuccessAsync(
- await token.transfer.sendTransactionAsync(receiver, amountToTransfer, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const finalOwnerBalance = await token.balanceOf.callAsync(owner);
- const finalReceiverBalance = await token.balanceOf.callAsync(receiver);
-
- const expectedFinalOwnerBalance = initOwnerBalance.minus(amountToTransfer);
- const expectedFinalReceiverBalance = amountToTransfer;
- expect(finalOwnerBalance).to.be.bignumber.equal(expectedFinalOwnerBalance);
- expect(finalReceiverBalance).to.be.bignumber.equal(expectedFinalReceiverBalance);
- });
-
- it('should return true on a 0 value transfer', async () => {
- const didReturnTrue = await token.transfer.callAsync(spender, new BigNumber(0), {
- from: owner,
- });
- expect(didReturnTrue).to.be.true();
- });
- });
-
- describe('transferFrom', () => {
- it('should throw if owner has insufficient balance', async () => {
- const ownerBalance = await token.balanceOf.callAsync(owner);
- const amountToTransfer = ownerBalance.plus(1);
- await web3Wrapper.awaitTransactionSuccessAsync(
- await token.approve.sendTransactionAsync(spender, amountToTransfer, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- return expectContractCallFailedAsync(
- token.transferFrom.callAsync(owner, spender, amountToTransfer, {
- from: spender,
- }),
- RevertReason.Erc20InsufficientBalance,
- );
- });
-
- it('should throw if spender has insufficient allowance', async () => {
- const ownerBalance = await token.balanceOf.callAsync(owner);
- const amountToTransfer = ownerBalance;
-
- const spenderAllowance = await token.allowance.callAsync(owner, spender);
- const isSpenderAllowanceInsufficient = spenderAllowance.cmp(amountToTransfer) < 0;
- expect(isSpenderAllowanceInsufficient).to.be.true();
-
- return expectContractCallFailedAsync(
- token.transferFrom.callAsync(owner, spender, amountToTransfer, {
- from: spender,
- }),
- RevertReason.Erc20InsufficientAllowance,
- );
- });
-
- it('should return true on a 0 value transfer', async () => {
- const amountToTransfer = new BigNumber(0);
- const didReturnTrue = await token.transferFrom.callAsync(owner, spender, amountToTransfer, {
- from: spender,
- });
- expect(didReturnTrue).to.be.true();
- });
-
- it('should not modify spender allowance if spender allowance is 2^256 - 1', async () => {
- const initOwnerBalance = await token.balanceOf.callAsync(owner);
- const amountToTransfer = initOwnerBalance;
- const initSpenderAllowance = constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS;
- await web3Wrapper.awaitTransactionSuccessAsync(
- await token.approve.sendTransactionAsync(spender, initSpenderAllowance, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await token.transferFrom.sendTransactionAsync(owner, spender, amountToTransfer, {
- from: spender,
- gas: constants.MAX_TOKEN_TRANSFERFROM_GAS,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
-
- const newSpenderAllowance = await token.allowance.callAsync(owner, spender);
- expect(initSpenderAllowance).to.be.bignumber.equal(newSpenderAllowance);
- });
-
- it('should transfer the correct balances if spender has sufficient allowance', async () => {
- const initOwnerBalance = await token.balanceOf.callAsync(owner);
- const amountToTransfer = initOwnerBalance;
- const initSpenderAllowance = initOwnerBalance;
- await web3Wrapper.awaitTransactionSuccessAsync(
- await token.approve.sendTransactionAsync(spender, initSpenderAllowance, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await token.transferFrom.sendTransactionAsync(owner, spender, amountToTransfer, {
- from: spender,
- gas: constants.MAX_TOKEN_TRANSFERFROM_GAS,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
-
- const newOwnerBalance = await token.balanceOf.callAsync(owner);
- const newSpenderBalance = await token.balanceOf.callAsync(spender);
-
- expect(newOwnerBalance).to.be.bignumber.equal(0);
- expect(newSpenderBalance).to.be.bignumber.equal(initOwnerBalance);
- });
-
- it('should modify allowance if spender has sufficient allowance less than 2^256 - 1', async () => {
- const initOwnerBalance = await token.balanceOf.callAsync(owner);
- const amountToTransfer = initOwnerBalance;
- const initSpenderAllowance = initOwnerBalance;
- await web3Wrapper.awaitTransactionSuccessAsync(
- await token.approve.sendTransactionAsync(spender, initSpenderAllowance, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await token.transferFrom.sendTransactionAsync(owner, spender, amountToTransfer, {
- from: spender,
- gas: constants.MAX_TOKEN_TRANSFERFROM_GAS,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
-
- const newSpenderAllowance = await token.allowance.callAsync(owner, spender);
- expect(newSpenderAllowance).to.be.bignumber.equal(0);
- });
- });
-});
diff --git a/packages/contracts/test/tokens/weth9.ts b/packages/contracts/test/tokens/weth9.ts
deleted file mode 100644
index 9a31dc3f2..000000000
--- a/packages/contracts/test/tokens/weth9.ts
+++ /dev/null
@@ -1,138 +0,0 @@
-import { BlockchainLifecycle } from '@0x/dev-utils';
-import { BigNumber } from '@0x/utils';
-import { Web3Wrapper } from '@0x/web3-wrapper';
-import * as chai from 'chai';
-
-import { WETH9Contract } from '../../generated-wrappers/weth9';
-import { artifacts } from '../../src/artifacts';
-import { expectInsufficientFundsAsync, expectTransactionFailedWithoutReasonAsync } from '../utils/assertions';
-import { chaiSetup } from '../utils/chai_setup';
-import { constants } from '../utils/constants';
-import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper';
-
-chaiSetup.configure();
-const expect = chai.expect;
-const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
-
-describe('EtherToken', () => {
- let account: string;
- const gasPrice = Web3Wrapper.toBaseUnitAmount(new BigNumber(20), 9);
- let etherToken: WETH9Contract;
-
- before(async () => {
- await blockchainLifecycle.startAsync();
- });
- after(async () => {
- await blockchainLifecycle.revertAsync();
- });
- before(async () => {
- const accounts = await web3Wrapper.getAvailableAddressesAsync();
- account = accounts[0];
-
- etherToken = await WETH9Contract.deployFrom0xArtifactAsync(artifacts.WETH9, provider, {
- gasPrice,
- ...txDefaults,
- });
- });
- beforeEach(async () => {
- await blockchainLifecycle.startAsync();
- });
- afterEach(async () => {
- await blockchainLifecycle.revertAsync();
- });
- describe('deposit', () => {
- it('should throw if caller attempts to deposit more Ether than caller balance', async () => {
- const initEthBalance = await web3Wrapper.getBalanceInWeiAsync(account);
- const ethToDeposit = initEthBalance.plus(1);
-
- return expectInsufficientFundsAsync(etherToken.deposit.sendTransactionAsync({ value: ethToDeposit }));
- });
-
- it('should convert deposited Ether to wrapped Ether tokens', async () => {
- const initEthBalance = await web3Wrapper.getBalanceInWeiAsync(account);
- const initEthTokenBalance = await etherToken.balanceOf.callAsync(account);
-
- const ethToDeposit = new BigNumber(Web3Wrapper.toWei(new BigNumber(1)));
-
- const txHash = await etherToken.deposit.sendTransactionAsync({ value: ethToDeposit });
- const receipt = await web3Wrapper.awaitTransactionSuccessAsync(
- txHash,
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
-
- const ethSpentOnGas = gasPrice.times(receipt.gasUsed);
- const finalEthBalance = await web3Wrapper.getBalanceInWeiAsync(account);
- const finalEthTokenBalance = await etherToken.balanceOf.callAsync(account);
-
- expect(finalEthBalance).to.be.bignumber.equal(initEthBalance.minus(ethToDeposit.plus(ethSpentOnGas)));
- expect(finalEthTokenBalance).to.be.bignumber.equal(initEthTokenBalance.plus(ethToDeposit));
- });
- });
-
- describe('withdraw', () => {
- it('should throw if caller attempts to withdraw greater than caller balance', async () => {
- const initEthTokenBalance = await etherToken.balanceOf.callAsync(account);
- const ethTokensToWithdraw = initEthTokenBalance.plus(1);
-
- return expectTransactionFailedWithoutReasonAsync(
- etherToken.withdraw.sendTransactionAsync(ethTokensToWithdraw),
- );
- });
-
- it('should convert ether tokens to ether with sufficient balance', async () => {
- const ethToDeposit = new BigNumber(Web3Wrapper.toWei(new BigNumber(1)));
- await web3Wrapper.awaitTransactionSuccessAsync(
- await etherToken.deposit.sendTransactionAsync({ value: ethToDeposit }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const initEthTokenBalance = await etherToken.balanceOf.callAsync(account);
- const initEthBalance = await web3Wrapper.getBalanceInWeiAsync(account);
- const ethTokensToWithdraw = initEthTokenBalance;
- expect(ethTokensToWithdraw).to.not.be.bignumber.equal(0);
- const txHash = await etherToken.withdraw.sendTransactionAsync(ethTokensToWithdraw, {
- gas: constants.MAX_ETHERTOKEN_WITHDRAW_GAS,
- });
- const receipt = await web3Wrapper.awaitTransactionSuccessAsync(
- txHash,
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
-
- const ethSpentOnGas = gasPrice.times(receipt.gasUsed);
- const finalEthBalance = await web3Wrapper.getBalanceInWeiAsync(account);
- const finalEthTokenBalance = await etherToken.balanceOf.callAsync(account);
-
- expect(finalEthBalance).to.be.bignumber.equal(
- initEthBalance.plus(ethTokensToWithdraw.minus(ethSpentOnGas)),
- );
- expect(finalEthTokenBalance).to.be.bignumber.equal(initEthTokenBalance.minus(ethTokensToWithdraw));
- });
- });
-
- describe('fallback', () => {
- it('should convert sent ether to ether tokens', async () => {
- const initEthBalance = await web3Wrapper.getBalanceInWeiAsync(account);
- const initEthTokenBalance = await etherToken.balanceOf.callAsync(account);
-
- const ethToDeposit = Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 18);
-
- const txHash = await web3Wrapper.sendTransactionAsync({
- from: account,
- to: etherToken.address,
- value: ethToDeposit,
- gasPrice,
- });
-
- const receipt = await web3Wrapper.awaitTransactionSuccessAsync(
- txHash,
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
-
- const ethSpentOnGas = gasPrice.times(receipt.gasUsed);
- const finalEthBalance = await web3Wrapper.getBalanceInWeiAsync(account);
- const finalEthTokenBalance = await etherToken.balanceOf.callAsync(account);
-
- expect(finalEthBalance).to.be.bignumber.equal(initEthBalance.minus(ethToDeposit.plus(ethSpentOnGas)));
- expect(finalEthTokenBalance).to.be.bignumber.equal(initEthTokenBalance.plus(ethToDeposit));
- });
- });
-});
diff --git a/packages/contracts/test/tokens/zrx_token.ts b/packages/contracts/test/tokens/zrx_token.ts
deleted file mode 100644
index cab62c205..000000000
--- a/packages/contracts/test/tokens/zrx_token.ts
+++ /dev/null
@@ -1,206 +0,0 @@
-import { BlockchainLifecycle } from '@0x/dev-utils';
-import { BigNumber } from '@0x/utils';
-import { Web3Wrapper } from '@0x/web3-wrapper';
-import * as chai from 'chai';
-
-import { ZRXTokenContract } from '../../generated-wrappers/zrx_token';
-import { artifacts } from '../../src/artifacts';
-import { chaiSetup } from '../utils/chai_setup';
-import { constants } from '../utils/constants';
-import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper';
-
-chaiSetup.configure();
-const expect = chai.expect;
-const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
-
-describe('ZRXToken', () => {
- let owner: string;
- let spender: string;
- let MAX_UINT: BigNumber;
- let zrxToken: ZRXTokenContract;
-
- before(async () => {
- await blockchainLifecycle.startAsync();
- });
- after(async () => {
- await blockchainLifecycle.revertAsync();
- });
- before(async () => {
- const accounts = await web3Wrapper.getAvailableAddressesAsync();
- owner = accounts[0];
- spender = accounts[1];
- zrxToken = await ZRXTokenContract.deployFrom0xArtifactAsync(artifacts.ZRXToken, provider, txDefaults);
- MAX_UINT = constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS;
- });
- beforeEach(async () => {
- await blockchainLifecycle.startAsync();
- });
- afterEach(async () => {
- await blockchainLifecycle.revertAsync();
- });
- describe('constants', () => {
- it('should have 18 decimals', async () => {
- const decimals = new BigNumber(await zrxToken.decimals.callAsync());
- const expectedDecimals = 18;
- expect(decimals).to.be.bignumber.equal(expectedDecimals);
- });
-
- it('should have a total supply of 1 billion tokens', async () => {
- const totalSupply = new BigNumber(await zrxToken.totalSupply.callAsync());
- const expectedTotalSupply = 1000000000;
- expect(Web3Wrapper.toUnitAmount(totalSupply, 18)).to.be.bignumber.equal(expectedTotalSupply);
- });
-
- it('should be named 0x Protocol Token', async () => {
- const name = await zrxToken.name.callAsync();
- const expectedName = '0x Protocol Token';
- expect(name).to.be.equal(expectedName);
- });
-
- it('should have the symbol ZRX', async () => {
- const symbol = await zrxToken.symbol.callAsync();
- const expectedSymbol = 'ZRX';
- expect(symbol).to.be.equal(expectedSymbol);
- });
- });
-
- describe('constructor', () => {
- it('should initialize owner balance to totalSupply', async () => {
- const ownerBalance = await zrxToken.balanceOf.callAsync(owner);
- const totalSupply = new BigNumber(await zrxToken.totalSupply.callAsync());
- expect(totalSupply).to.be.bignumber.equal(ownerBalance);
- });
- });
-
- describe('transfer', () => {
- it('should transfer balance from sender to receiver', async () => {
- const receiver = spender;
- const initOwnerBalance = await zrxToken.balanceOf.callAsync(owner);
- const amountToTransfer = new BigNumber(1);
- await web3Wrapper.awaitTransactionSuccessAsync(
- await zrxToken.transfer.sendTransactionAsync(receiver, amountToTransfer, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const finalOwnerBalance = await zrxToken.balanceOf.callAsync(owner);
- const finalReceiverBalance = await zrxToken.balanceOf.callAsync(receiver);
-
- const expectedFinalOwnerBalance = initOwnerBalance.minus(amountToTransfer);
- const expectedFinalReceiverBalance = amountToTransfer;
- expect(finalOwnerBalance).to.be.bignumber.equal(expectedFinalOwnerBalance);
- expect(finalReceiverBalance).to.be.bignumber.equal(expectedFinalReceiverBalance);
- });
-
- it('should return true on a 0 value transfer', async () => {
- const didReturnTrue = await zrxToken.transfer.callAsync(spender, new BigNumber(0), {
- from: owner,
- });
- expect(didReturnTrue).to.be.true();
- });
- });
-
- describe('transferFrom', () => {
- it('should return false if owner has insufficient balance', async () => {
- const ownerBalance = await zrxToken.balanceOf.callAsync(owner);
- const amountToTransfer = ownerBalance.plus(1);
- await web3Wrapper.awaitTransactionSuccessAsync(
- await zrxToken.approve.sendTransactionAsync(spender, amountToTransfer, {
- from: owner,
- gas: constants.MAX_TOKEN_APPROVE_GAS,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const didReturnTrue = await zrxToken.transferFrom.callAsync(owner, spender, amountToTransfer, {
- from: spender,
- });
- expect(didReturnTrue).to.be.false();
- });
-
- it('should return false if spender has insufficient allowance', async () => {
- const ownerBalance = await zrxToken.balanceOf.callAsync(owner);
- const amountToTransfer = ownerBalance;
-
- const spenderAllowance = await zrxToken.allowance.callAsync(owner, spender);
- const isSpenderAllowanceInsufficient = spenderAllowance.cmp(amountToTransfer) < 0;
- expect(isSpenderAllowanceInsufficient).to.be.true();
-
- const didReturnTrue = await zrxToken.transferFrom.callAsync(owner, spender, amountToTransfer, {
- from: spender,
- });
- expect(didReturnTrue).to.be.false();
- });
-
- it('should return true on a 0 value transfer', async () => {
- const amountToTransfer = new BigNumber(0);
- const didReturnTrue = await zrxToken.transferFrom.callAsync(owner, spender, amountToTransfer, {
- from: spender,
- });
- expect(didReturnTrue).to.be.true();
- });
-
- it('should not modify spender allowance if spender allowance is 2^256 - 1', async () => {
- const initOwnerBalance = await zrxToken.balanceOf.callAsync(owner);
- const amountToTransfer = initOwnerBalance;
- const initSpenderAllowance = MAX_UINT;
- await web3Wrapper.awaitTransactionSuccessAsync(
- await zrxToken.approve.sendTransactionAsync(spender, initSpenderAllowance, {
- from: owner,
- gas: constants.MAX_TOKEN_APPROVE_GAS,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await zrxToken.transferFrom.sendTransactionAsync(owner, spender, amountToTransfer, {
- from: spender,
- gas: constants.MAX_TOKEN_TRANSFERFROM_GAS,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
-
- const newSpenderAllowance = await zrxToken.allowance.callAsync(owner, spender);
- expect(initSpenderAllowance).to.be.bignumber.equal(newSpenderAllowance);
- });
-
- it('should transfer the correct balances if spender has sufficient allowance', async () => {
- const initOwnerBalance = await zrxToken.balanceOf.callAsync(owner);
- const initSpenderBalance = await zrxToken.balanceOf.callAsync(spender);
- const amountToTransfer = initOwnerBalance;
- const initSpenderAllowance = initOwnerBalance;
- await web3Wrapper.awaitTransactionSuccessAsync(
- await zrxToken.approve.sendTransactionAsync(spender, initSpenderAllowance),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await zrxToken.transferFrom.sendTransactionAsync(owner, spender, amountToTransfer, {
- from: spender,
- gas: constants.MAX_TOKEN_TRANSFERFROM_GAS,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
-
- const newOwnerBalance = await zrxToken.balanceOf.callAsync(owner);
- const newSpenderBalance = await zrxToken.balanceOf.callAsync(spender);
-
- expect(newOwnerBalance).to.be.bignumber.equal(0);
- expect(newSpenderBalance).to.be.bignumber.equal(initSpenderBalance.plus(initOwnerBalance));
- });
-
- it('should modify allowance if spender has sufficient allowance less than 2^256 - 1', async () => {
- const initOwnerBalance = await zrxToken.balanceOf.callAsync(owner);
- const amountToTransfer = initOwnerBalance;
- await web3Wrapper.awaitTransactionSuccessAsync(
- await zrxToken.approve.sendTransactionAsync(spender, amountToTransfer),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await zrxToken.transferFrom.sendTransactionAsync(owner, spender, amountToTransfer, {
- from: spender,
- gas: constants.MAX_TOKEN_TRANSFERFROM_GAS,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
-
- const newSpenderAllowance = await zrxToken.allowance.callAsync(owner, spender);
- expect(newSpenderAllowance).to.be.bignumber.equal(0);
- });
- });
-});
diff --git a/packages/contracts/test/tutorials/arbitrage.ts b/packages/contracts/test/tutorials/arbitrage.ts
deleted file mode 100644
index 78e0bc238..000000000
--- a/packages/contracts/test/tutorials/arbitrage.ts
+++ /dev/null
@@ -1,260 +0,0 @@
-// import { ECSignature, SignedOrder, ZeroEx } from '0x.js';
-// import { BlockchainLifecycle, devConstants, web3Factory } from '@0x/dev-utils';
-// import { ExchangeContractErrs } from 'ethereum-types';
-// import { BigNumber } from '@0x/utils';
-// import { Web3Wrapper } from '@0x/web3-wrapper';
-// import * as chai from 'chai';
-// import ethUtil = require('ethereumjs-util');
-// import * as Web3 from 'web3';
-
-// import { AccountLevelsContract } from '../../src/generated_contract_wrappers/account_levels';
-// import { ArbitrageContract } from '../../src/generated_contract_wrappers/arbitrage';
-// import { DummyTokenContract } from '../../src/generated_contract_wrappers/dummy_token';
-// import { EtherDeltaContract } from '../../src/generated_contract_wrappers/ether_delta';
-// import { ExchangeContract } from '../../src/generated_contract_wrappers/exchange';
-// import { TokenTransferProxyContract } from '../../src/generated_contract_wrappers/token_transfer_proxy';
-// import { artifacts } from '../../util/artifacts';
-// import { Balances } from '../../util/balances';
-// import { constants } from '../../util/constants';
-// import { crypto } from '../../util/crypto';
-// import { ExchangeWrapper } from '../../util/exchange_wrapper';
-// import { OrderFactory } from '../../util/order_factory';
-// import { BalancesByOwner, ContractName } from '../../util/types';
-// import { chaiSetup } from '../utils/chai_setup';
-
-// import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper';
-
-// chaiSetup.configure();
-// const expect = chai.expect;
-// const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
-
-// describe('Arbitrage', () => {
-// let coinbase: string;
-// let maker: string;
-// let edMaker: string;
-// let edFrontRunner: string;
-// let amountGet: BigNumber;
-// let amountGive: BigNumber;
-// let makerTokenAmount: BigNumber;
-// let takerTokenAmount: BigNumber;
-// const feeRecipient = constants.NULL_ADDRESS;
-// const INITIAL_BALANCE = ZeroEx.toBaseUnitAmount(new BigNumber(10000), 18);
-// const INITIAL_ALLOWANCE = ZeroEx.toBaseUnitAmount(new BigNumber(10000), 18);
-
-// let weth: DummyTokenContract;
-// let zrx: DummyTokenContract;
-// let arbitrage: ArbitrageContract;
-// let etherDelta: EtherDeltaContract;
-
-// let signedOrder: SignedOrder;
-// let exWrapper: ExchangeWrapper;
-// let orderFactory: OrderFactory;
-
-// let zeroEx: ZeroEx;
-
-// // From a bird's eye view - we create two orders.
-// // 0x order of 1 ZRX (maker) for 1 WETH (taker)
-// // ED order of 2 WETH (tokenGive) for 1 ZRX (tokenGet)
-// // And then we do an atomic arbitrage between them which gives us 1 WETH.
-// before(async () => {
-// const accounts = await web3Wrapper.getAvailableAddressesAsync();
-// [coinbase, maker, edMaker, edFrontRunner] = accounts;
-// weth = await DummyTokenContract.deployFrom0xArtifactAsync(
-// artifacts.DummyToken,
-// provider,
-// txDefaults,
-// constants.DUMMY_TOKEN_NAME,
-// constants.DUMMY_TOKEN_SYMBOL,
-// constants.DUMMY_TOKEN_DECIMALS,
-// constants.DUMMY_TOKEN_TOTAL_SUPPLY,
-// );
-// zrx = await DummyTokenContract.deployFrom0xArtifactAsync(
-// artifacts.DummyToken,
-// provider,
-// txDefaults,
-// constants.DUMMY_TOKEN_NAME,
-// constants.DUMMY_TOKEN_SYMBOL,
-// constants.DUMMY_TOKEN_DECIMALS,
-// constants.DUMMY_TOKEN_TOTAL_SUPPLY,
-// );
-// const accountLevels = await AccountLevelsContract.deployFrom0xArtifactAsync(
-// artifacts.AccountLevels,
-// provider,
-// txDefaults,
-// );
-// const edAdminAddress = accounts[0];
-// const edMakerFee = new BigNumber(0);
-// const edTakerFee = new BigNumber(0);
-// const edFeeRebate = new BigNumber(0);
-// etherDelta = await EtherDeltaContract.deployFrom0xArtifactAsync(
-// artifacts.EtherDelta,
-// provider,
-// txDefaults,
-// edAdminAddress,
-// feeRecipient,
-// accountLevels.address,
-// edMakerFee,
-// edTakerFee,
-// edFeeRebate,
-// );
-// const tokenTransferProxy = await TokenTransferProxyContract.deployFrom0xArtifactAsync(
-// artifacts.TokenTransferProxy,
-// provider,
-// txDefaults,
-// );
-// const exchange = await ExchangeContract.deployFrom0xArtifactAsync(
-// artifacts.Exchange,
-// provider,
-// txDefaults,
-// zrx.address,
-// tokenTransferProxy.address,
-// );
-// await tokenTransferProxy.addAuthorizedAddress.sendTransactionAsync(exchange.address, { from: accounts[0] });
-// zeroEx = new ZeroEx(provider, {
-// exchangeContractAddress: exchange.address,
-// networkId: constants.TESTRPC_NETWORK_ID,
-// });
-// exWrapper = new ExchangeWrapper(exchange, provider);
-
-// makerTokenAmount = ZeroEx.toBaseUnitAmount(new BigNumber(1), 18);
-// takerTokenAmount = makerTokenAmount;
-// const defaultOrderParams = {
-// exchangeContractAddress: exchange.address,
-// maker,
-// feeRecipient,
-// makerTokenAddress: zrx.address,
-// takerTokenAddress: weth.address,
-// makerTokenAmount,
-// takerTokenAmount,
-// makerFee: new BigNumber(0),
-// takerFee: new BigNumber(0),
-// };
-// orderFactory = new OrderFactory(zeroEx, defaultOrderParams);
-// arbitrage = await ArbitrageContract.deployFrom0xArtifactAsync(
-// artifacts.Arbitrage,
-// provider,
-// txDefaults,
-// exchange.address,
-// etherDelta.address,
-// tokenTransferProxy.address,
-// );
-// // Enable arbitrage and withdrawals of tokens
-// await arbitrage.setAllowances.sendTransactionAsync(weth.address, { from: coinbase });
-// await arbitrage.setAllowances.sendTransactionAsync(zrx.address, { from: coinbase });
-
-// // Give some tokens to arbitrage contract
-// await weth.setBalance.sendTransactionAsync(arbitrage.address, takerTokenAmount, { from: coinbase });
-
-// // Fund the maker on exchange side
-// await zrx.setBalance.sendTransactionAsync(maker, makerTokenAmount, { from: coinbase });
-// // Set the allowance for the maker on Exchange side
-// await zrx.approve.sendTransactionAsync(tokenTransferProxy.address, INITIAL_ALLOWANCE, { from: maker });
-
-// amountGive = ZeroEx.toBaseUnitAmount(new BigNumber(2), 18);
-// // Fund the maker on EtherDelta side
-// await weth.setBalance.sendTransactionAsync(edMaker, amountGive, { from: coinbase });
-// // Set the allowance for the maker on EtherDelta side
-// await weth.approve.sendTransactionAsync(etherDelta.address, INITIAL_ALLOWANCE, { from: edMaker });
-// // Deposit maker funds into EtherDelta
-// await etherDelta.depositToken.sendTransactionAsync(weth.address, amountGive, { from: edMaker });
-
-// amountGet = makerTokenAmount;
-// // Fund the front runner on EtherDelta side
-// await zrx.setBalance.sendTransactionAsync(edFrontRunner, amountGet, { from: coinbase });
-// // Set the allowance for the front-runner on EtherDelta side
-// await zrx.approve.sendTransactionAsync(etherDelta.address, INITIAL_ALLOWANCE, { from: edFrontRunner });
-// // Deposit front runner funds into EtherDelta
-// await etherDelta.depositToken.sendTransactionAsync(zrx.address, amountGet, { from: edFrontRunner });
-// });
-// beforeEach(async () => {
-// await blockchainLifecycle.startAsync();
-// });
-// afterEach(async () => {
-// await blockchainLifecycle.revertAsync();
-// });
-// describe('makeAtomicTrade', () => {
-// let addresses: string[];
-// let values: BigNumber[];
-// let v: number[];
-// let r: string[];
-// let s: string[];
-// let tokenGet: string;
-// let tokenGive: string;
-// let expires: BigNumber;
-// let nonce: BigNumber;
-// let edSignature: ECSignature;
-// before(async () => {
-// signedOrder = await orderFactory.newSignedOrderAsync();
-// tokenGet = zrx.address;
-// tokenGive = weth.address;
-// const blockNumber = await web3Wrapper.getBlockNumberAsync();
-// const ED_ORDER_EXPIRATION_IN_BLOCKS = 10;
-// expires = new BigNumber(blockNumber + ED_ORDER_EXPIRATION_IN_BLOCKS);
-// nonce = new BigNumber(42);
-// const edOrderHash = `0x${crypto
-// .solSHA256([etherDelta.address, tokenGet, amountGet, tokenGive, amountGive, expires, nonce])
-// .toString('hex')}`;
-// const shouldAddPersonalMessagePrefix = false;
-// edSignature = await zeroEx.signOrderHashAsync(edOrderHash, edMaker, shouldAddPersonalMessagePrefix);
-// addresses = [
-// signedOrder.maker,
-// signedOrder.taker,
-// signedOrder.makerTokenAddress,
-// signedOrder.takerTokenAddress,
-// signedOrder.feeRecipient,
-// edMaker,
-// ];
-// const fillTakerTokenAmount = takerTokenAmount;
-// const edFillAmount = makerTokenAmount;
-// values = [
-// signedOrder.makerTokenAmount,
-// signedOrder.takerTokenAmount,
-// signedOrder.makerFee,
-// signedOrder.takerFee,
-// signedOrder.expirationUnixTimestampSec,
-// signedOrder.salt,
-// fillTakerTokenAmount,
-// amountGet,
-// amountGive,
-// expires,
-// nonce,
-// edFillAmount,
-// ];
-// v = [signedOrder.ecSignature.v, edSignature.v];
-// r = [signedOrder.ecSignature.r, edSignature.r];
-// s = [signedOrder.ecSignature.s, edSignature.s];
-// });
-// it('should successfully execute the arbitrage if not front-runned', async () => {
-// const txHash = await arbitrage.makeAtomicTrade.sendTransactionAsync(addresses, values, v, r, s, {
-// from: coinbase,
-// });
-// const res = await zeroEx.awaitTransactionMinedAsync(txHash);
-// const postBalance = await weth.balanceOf.callAsync(arbitrage.address);
-// expect(postBalance).to.be.bignumber.equal(amountGive);
-// });
-// it('should fail and revert if front-runned', async () => {
-// const preBalance = await weth.balanceOf.callAsync(arbitrage.address);
-// // Front-running transaction
-// await etherDelta.trade.sendTransactionAsync(
-// tokenGet,
-// amountGet,
-// tokenGive,
-// amountGive,
-// expires,
-// nonce,
-// edMaker,
-// edSignature.v,
-// edSignature.r,
-// edSignature.s,
-// amountGet,
-// { from: edFrontRunner },
-// );
-// // tslint:disable-next-line:await-promise
-// await expect(
-// arbitrage.makeAtomicTrade.sendTransactionAsync(addresses, values, v, r, s, { from: coinbase }),
-// ).to.be.rejectedWith(constants.REVERT);
-// const postBalance = await weth.balanceOf.callAsync(arbitrage.address);
-// expect(preBalance).to.be.bignumber.equal(postBalance);
-// });
-// });
-// });
diff --git a/packages/contracts/test/utils/abstract_asset_wrapper.ts b/packages/contracts/test/utils/abstract_asset_wrapper.ts
deleted file mode 100644
index 4b56a8502..000000000
--- a/packages/contracts/test/utils/abstract_asset_wrapper.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-export abstract class AbstractAssetWrapper {
- public abstract getProxyId(): string;
-}
diff --git a/packages/contracts/test/utils/address_utils.ts b/packages/contracts/test/utils/address_utils.ts
deleted file mode 100644
index 634da0c16..000000000
--- a/packages/contracts/test/utils/address_utils.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import { generatePseudoRandomSalt } from '@0x/order-utils';
-import { crypto } from '@0x/order-utils/lib/src/crypto';
-
-export const addressUtils = {
- generatePseudoRandomAddress(): string {
- const randomBigNum = generatePseudoRandomSalt();
- const randomBuff = crypto.solSHA3([randomBigNum]);
- const randomAddress = `0x${randomBuff.slice(0, 20).toString('hex')}`;
- return randomAddress;
- },
-};
diff --git a/packages/contracts/test/utils/assertions.ts b/packages/contracts/test/utils/assertions.ts
deleted file mode 100644
index 5b1cedfcc..000000000
--- a/packages/contracts/test/utils/assertions.ts
+++ /dev/null
@@ -1,199 +0,0 @@
-import { RevertReason } from '@0x/types';
-import { logUtils } from '@0x/utils';
-import { NodeType } from '@0x/web3-wrapper';
-import * as chai from 'chai';
-import { TransactionReceipt, TransactionReceiptStatus, TransactionReceiptWithDecodedLogs } from 'ethereum-types';
-import * as _ from 'lodash';
-
-import { web3Wrapper } from './web3_wrapper';
-
-const expect = chai.expect;
-
-let nodeType: NodeType | undefined;
-
-// Represents the return value of a `sendTransaction` call. The Promise should
-// resolve with either a transaction receipt or a transaction hash.
-export type sendTransactionResult = Promise<TransactionReceipt | TransactionReceiptWithDecodedLogs | string>;
-
-/**
- * Returns ganacheError if the backing Ethereum node is Ganache and gethError
- * if it is Geth.
- * @param ganacheError the error to be returned if the backing node is Ganache.
- * @param gethError the error to be returned if the backing node is Geth.
- * @returns either the given ganacheError or gethError depending on the backing
- * node.
- */
-async function _getGanacheOrGethError(ganacheError: string, gethError: string): Promise<string> {
- if (_.isUndefined(nodeType)) {
- nodeType = await web3Wrapper.getNodeTypeAsync();
- }
- switch (nodeType) {
- case NodeType.Ganache:
- return ganacheError;
- case NodeType.Geth:
- return gethError;
- default:
- throw new Error(`Unknown node type: ${nodeType}`);
- }
-}
-
-async function _getInsufficientFundsErrorMessageAsync(): Promise<string> {
- return _getGanacheOrGethError("sender doesn't have enough funds", 'insufficient funds');
-}
-
-async function _getTransactionFailedErrorMessageAsync(): Promise<string> {
- return _getGanacheOrGethError('revert', 'always failing transaction');
-}
-
-async function _getContractCallFailedErrorMessageAsync(): Promise<string> {
- return _getGanacheOrGethError('revert', 'Contract call failed');
-}
-
-/**
- * Returns the expected error message for an 'invalid opcode' resulting from a
- * contract call. The exact error message depends on the backing Ethereum node.
- */
-export async function getInvalidOpcodeErrorMessageForCallAsync(): Promise<string> {
- return _getGanacheOrGethError('invalid opcode', 'Contract call failed');
-}
-
-/**
- * Returns the expected error message for the given revert reason resulting from
- * a sendTransaction call. The exact error message depends on the backing
- * Ethereum node and whether it supports revert reasons.
- * @param reason a specific revert reason.
- * @returns the expected error message.
- */
-export async function getRevertReasonOrErrorMessageForSendTransactionAsync(reason: RevertReason): Promise<string> {
- return _getGanacheOrGethError(reason, 'always failing transaction');
-}
-
-/**
- * Rejects if the given Promise does not reject with an error indicating
- * insufficient funds.
- * @param p a promise resulting from a contract call or sendTransaction call.
- * @returns a new Promise which will reject if the conditions are not met and
- * otherwise resolve with no value.
- */
-export async function expectInsufficientFundsAsync<T>(p: Promise<T>): Promise<void> {
- const errMessage = await _getInsufficientFundsErrorMessageAsync();
- return expect(p).to.be.rejectedWith(errMessage);
-}
-
-/**
- * Resolves if the the sendTransaction call fails with the given revert reason.
- * However, since Geth does not support revert reasons for sendTransaction, this
- * falls back to expectTransactionFailedWithoutReasonAsync if the backing
- * Ethereum node is Geth.
- * @param p a Promise resulting from a sendTransaction call
- * @param reason a specific revert reason
- * @returns a new Promise which will reject if the conditions are not met and
- * otherwise resolve with no value.
- */
-export async function expectTransactionFailedAsync(p: sendTransactionResult, reason: RevertReason): Promise<void> {
- // HACK(albrow): This dummy `catch` should not be necessary, but if you
- // remove it, there is an uncaught exception and the Node process will
- // forcibly exit. It's possible this is a false positive in
- // make-promises-safe.
- p.catch(e => {
- _.noop(e);
- });
-
- if (_.isUndefined(nodeType)) {
- nodeType = await web3Wrapper.getNodeTypeAsync();
- }
- switch (nodeType) {
- case NodeType.Ganache:
- return expect(p).to.be.rejectedWith(reason);
- case NodeType.Geth:
- logUtils.warn(
- 'WARNING: Geth does not support revert reasons for sendTransaction. This test will pass if the transaction fails for any reason.',
- );
- return expectTransactionFailedWithoutReasonAsync(p);
- default:
- throw new Error(`Unknown node type: ${nodeType}`);
- }
-}
-
-/**
- * Resolves if the transaction fails without a revert reason, or if the
- * corresponding transactionReceipt has a status of 0 or '0', indicating
- * failure.
- * @param p a Promise resulting from a sendTransaction call
- * @returns a new Promise which will reject if the conditions are not met and
- * otherwise resolve with no value.
- */
-export async function expectTransactionFailedWithoutReasonAsync(p: sendTransactionResult): Promise<void> {
- return p
- .then(async result => {
- let txReceiptStatus: TransactionReceiptStatus;
- if (_.isString(result)) {
- // Result is a txHash. We need to make a web3 call to get the
- // receipt, then get the status from the receipt.
- const txReceipt = await web3Wrapper.awaitTransactionMinedAsync(result);
- txReceiptStatus = txReceipt.status;
- } else if ('status' in result) {
- // Result is a transaction receipt, so we can get the status
- // directly.
- txReceiptStatus = result.status;
- } else {
- throw new Error('Unexpected result type: ' + typeof result);
- }
- expect(_.toString(txReceiptStatus)).to.equal(
- '0',
- 'Expected transaction to fail but receipt had a non-zero status, indicating success',
- );
- })
- .catch(async err => {
- // If the promise rejects, we expect a specific error message,
- // depending on the backing Ethereum node type.
- const errMessage = await _getTransactionFailedErrorMessageAsync();
- expect(err.message).to.include(errMessage);
- });
-}
-
-/**
- * Resolves if the the contract call fails with the given revert reason.
- * @param p a Promise resulting from a contract call
- * @param reason a specific revert reason
- * @returns a new Promise which will reject if the conditions are not met and
- * otherwise resolve with no value.
- */
-export async function expectContractCallFailedAsync<T>(p: Promise<T>, reason: RevertReason): Promise<void> {
- return expect(p).to.be.rejectedWith(reason);
-}
-
-/**
- * Resolves if the contract call fails without a revert reason.
- * @param p a Promise resulting from a contract call
- * @returns a new Promise which will reject if the conditions are not met and
- * otherwise resolve with no value.
- */
-export async function expectContractCallFailedWithoutReasonAsync<T>(p: Promise<T>): Promise<void> {
- const errMessage = await _getContractCallFailedErrorMessageAsync();
- return expect(p).to.be.rejectedWith(errMessage);
-}
-
-/**
- * Resolves if the contract creation/deployment fails without a revert reason.
- * @param p a Promise resulting from a contract creation/deployment
- * @returns a new Promise which will reject if the conditions are not met and
- * otherwise resolve with no value.
- */
-export async function expectContractCreationFailedAsync<T>(
- p: sendTransactionResult,
- reason: RevertReason,
-): Promise<void> {
- return expectTransactionFailedAsync(p, reason);
-}
-
-/**
- * Resolves if the contract creation/deployment fails without a revert reason.
- * @param p a Promise resulting from a contract creation/deployment
- * @returns a new Promise which will reject if the conditions are not met and
- * otherwise resolve with no value.
- */
-export async function expectContractCreationFailedWithoutReasonAsync<T>(p: Promise<T>): Promise<void> {
- const errMessage = await _getTransactionFailedErrorMessageAsync();
- return expect(p).to.be.rejectedWith(errMessage);
-}
diff --git a/packages/contracts/test/utils/asset_wrapper.ts b/packages/contracts/test/utils/asset_wrapper.ts
deleted file mode 100644
index 4e7696066..000000000
--- a/packages/contracts/test/utils/asset_wrapper.ts
+++ /dev/null
@@ -1,223 +0,0 @@
-import { assetDataUtils } from '@0x/order-utils';
-import { AssetProxyId } from '@0x/types';
-import { BigNumber, errorUtils } from '@0x/utils';
-import * as _ from 'lodash';
-
-import { AbstractAssetWrapper } from './abstract_asset_wrapper';
-import { constants } from './constants';
-import { ERC20Wrapper } from './erc20_wrapper';
-import { ERC721Wrapper } from './erc721_wrapper';
-
-interface ProxyIdToAssetWrappers {
- [proxyId: string]: AbstractAssetWrapper;
-}
-
-/**
- * This class abstracts away the differences between ERC20 and ERC721 tokens so that
- * the logic that uses it does not need to care what standard a token belongs to.
- */
-export class AssetWrapper {
- private readonly _proxyIdToAssetWrappers: ProxyIdToAssetWrappers;
- constructor(assetWrappers: AbstractAssetWrapper[]) {
- this._proxyIdToAssetWrappers = {};
- _.each(assetWrappers, assetWrapper => {
- const proxyId = assetWrapper.getProxyId();
- this._proxyIdToAssetWrappers[proxyId] = assetWrapper;
- });
- }
- public async getBalanceAsync(userAddress: string, assetData: string): Promise<BigNumber> {
- const proxyId = assetDataUtils.decodeAssetProxyId(assetData);
- switch (proxyId) {
- case AssetProxyId.ERC20: {
- const erc20Wrapper = this._proxyIdToAssetWrappers[proxyId] as ERC20Wrapper;
- const balance = await erc20Wrapper.getBalanceAsync(userAddress, assetData);
- return balance;
- }
- case AssetProxyId.ERC721: {
- const assetWrapper = this._proxyIdToAssetWrappers[proxyId] as ERC721Wrapper;
- const assetProxyData = assetDataUtils.decodeERC721AssetData(assetData);
- const isOwner = await assetWrapper.isOwnerAsync(
- userAddress,
- assetProxyData.tokenAddress,
- assetProxyData.tokenId,
- );
- const balance = isOwner ? new BigNumber(1) : new BigNumber(0);
- return balance;
- }
- default:
- throw errorUtils.spawnSwitchErr('proxyId', proxyId);
- }
- }
- public async setBalanceAsync(userAddress: string, assetData: string, desiredBalance: BigNumber): Promise<void> {
- const proxyId = assetDataUtils.decodeAssetProxyId(assetData);
- switch (proxyId) {
- case AssetProxyId.ERC20: {
- const erc20Wrapper = this._proxyIdToAssetWrappers[proxyId] as ERC20Wrapper;
- await erc20Wrapper.setBalanceAsync(userAddress, assetData, desiredBalance);
- return;
- }
- case AssetProxyId.ERC721: {
- if (!desiredBalance.eq(0) && !desiredBalance.eq(1)) {
- throw new Error(`Balance for ERC721 token can only be set to 0 or 1. Got: ${desiredBalance}`);
- }
- const erc721Wrapper = this._proxyIdToAssetWrappers[proxyId] as ERC721Wrapper;
- const assetProxyData = assetDataUtils.decodeERC721AssetData(assetData);
- const doesTokenExist = erc721Wrapper.doesTokenExistAsync(
- assetProxyData.tokenAddress,
- assetProxyData.tokenId,
- );
- if (!doesTokenExist && desiredBalance.eq(1)) {
- await erc721Wrapper.mintAsync(assetProxyData.tokenAddress, assetProxyData.tokenId, userAddress);
- return;
- } else if (!doesTokenExist && desiredBalance.eq(0)) {
- return; // noop
- }
- const tokenOwner = await erc721Wrapper.ownerOfAsync(
- assetProxyData.tokenAddress,
- assetProxyData.tokenId,
- );
- if (userAddress !== tokenOwner && desiredBalance.eq(1)) {
- await erc721Wrapper.transferFromAsync(
- assetProxyData.tokenAddress,
- assetProxyData.tokenId,
- tokenOwner,
- userAddress,
- );
- } else if (tokenOwner === userAddress && desiredBalance.eq(0)) {
- // Transfer token to someone else
- const userAddresses = await (erc721Wrapper as any)._web3Wrapper.getAvailableAddressesAsync();
- const nonOwner = _.find(userAddresses, a => a !== userAddress);
- await erc721Wrapper.transferFromAsync(
- assetProxyData.tokenAddress,
- assetProxyData.tokenId,
- tokenOwner,
- nonOwner,
- );
- return;
- } else if (
- (userAddress !== tokenOwner && desiredBalance.eq(0)) ||
- (tokenOwner === userAddress && desiredBalance.eq(1))
- ) {
- return; // noop
- }
- break;
- }
- default:
- throw errorUtils.spawnSwitchErr('proxyId', proxyId);
- }
- }
- public async getProxyAllowanceAsync(userAddress: string, assetData: string): Promise<BigNumber> {
- const proxyId = assetDataUtils.decodeAssetProxyId(assetData);
- switch (proxyId) {
- case AssetProxyId.ERC20: {
- const erc20Wrapper = this._proxyIdToAssetWrappers[proxyId] as ERC20Wrapper;
- const allowance = await erc20Wrapper.getProxyAllowanceAsync(userAddress, assetData);
- return allowance;
- }
- case AssetProxyId.ERC721: {
- const assetWrapper = this._proxyIdToAssetWrappers[proxyId] as ERC721Wrapper;
- const erc721ProxyData = assetDataUtils.decodeERC721AssetData(assetData);
- const isProxyApprovedForAll = await assetWrapper.isProxyApprovedForAllAsync(
- userAddress,
- erc721ProxyData.tokenAddress,
- );
- if (isProxyApprovedForAll) {
- return constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS;
- }
-
- const isProxyApproved = await assetWrapper.isProxyApprovedAsync(
- erc721ProxyData.tokenAddress,
- erc721ProxyData.tokenId,
- );
- const allowance = isProxyApproved ? new BigNumber(1) : new BigNumber(0);
- return allowance;
- }
- default:
- throw errorUtils.spawnSwitchErr('proxyId', proxyId);
- }
- }
- public async setProxyAllowanceAsync(
- userAddress: string,
- assetData: string,
- desiredAllowance: BigNumber,
- ): Promise<void> {
- const proxyId = assetDataUtils.decodeAssetProxyId(assetData);
- switch (proxyId) {
- case AssetProxyId.ERC20: {
- const erc20Wrapper = this._proxyIdToAssetWrappers[proxyId] as ERC20Wrapper;
- await erc20Wrapper.setAllowanceAsync(userAddress, assetData, desiredAllowance);
- return;
- }
- case AssetProxyId.ERC721: {
- if (
- !desiredAllowance.eq(0) &&
- !desiredAllowance.eq(1) &&
- !desiredAllowance.eq(constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS)
- ) {
- throw new Error(
- `Allowance for ERC721 token can only be set to 0, 1 or 2^256-1. Got: ${desiredAllowance}`,
- );
- }
- const erc721Wrapper = this._proxyIdToAssetWrappers[proxyId] as ERC721Wrapper;
- const assetProxyData = assetDataUtils.decodeERC721AssetData(assetData);
-
- const doesTokenExist = await erc721Wrapper.doesTokenExistAsync(
- assetProxyData.tokenAddress,
- assetProxyData.tokenId,
- );
- if (!doesTokenExist) {
- throw new Error(
- `Cannot setProxyAllowance on non-existent token: ${assetProxyData.tokenAddress} ${
- assetProxyData.tokenId
- }`,
- );
- }
- const isProxyApprovedForAll = await erc721Wrapper.isProxyApprovedForAllAsync(
- userAddress,
- assetProxyData.tokenAddress,
- );
- if (!isProxyApprovedForAll && desiredAllowance.eq(constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS)) {
- const isApproved = true;
- await erc721Wrapper.approveProxyForAllAsync(
- assetProxyData.tokenAddress,
- assetProxyData.tokenId,
- isApproved,
- );
- } else if (isProxyApprovedForAll && desiredAllowance.eq(0)) {
- const isApproved = false;
- await erc721Wrapper.approveProxyForAllAsync(
- assetProxyData.tokenAddress,
- assetProxyData.tokenId,
- isApproved,
- );
- } else if (isProxyApprovedForAll && desiredAllowance.eq(constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS)) {
- return; // Noop
- }
-
- const isProxyApproved = await erc721Wrapper.isProxyApprovedAsync(
- assetProxyData.tokenAddress,
- assetProxyData.tokenId,
- );
- if (!isProxyApproved && desiredAllowance.eq(1)) {
- await erc721Wrapper.approveProxyAsync(assetProxyData.tokenAddress, assetProxyData.tokenId);
- } else if (isProxyApproved && desiredAllowance.eq(0)) {
- // Remove approval
- await erc721Wrapper.approveAsync(
- constants.NULL_ADDRESS,
- assetProxyData.tokenAddress,
- assetProxyData.tokenId,
- );
- } else if (
- (!isProxyApproved && desiredAllowance.eq(0)) ||
- (isProxyApproved && desiredAllowance.eq(1))
- ) {
- return; // noop
- }
-
- break;
- }
- default:
- throw errorUtils.spawnSwitchErr('proxyId', proxyId);
- }
- }
-}
diff --git a/packages/contracts/test/utils/block_timestamp.ts b/packages/contracts/test/utils/block_timestamp.ts
deleted file mode 100644
index 66c13eed1..000000000
--- a/packages/contracts/test/utils/block_timestamp.ts
+++ /dev/null
@@ -1,43 +0,0 @@
-import * as _ from 'lodash';
-
-import { constants } from './constants';
-import { web3Wrapper } from './web3_wrapper';
-
-let firstAccount: string | undefined;
-
-/**
- * Increases time by the given number of seconds and then mines a block so that
- * the current block timestamp has the offset applied.
- * @param seconds the number of seconds by which to incrase the time offset.
- * @returns a new Promise which will resolve with the new total time offset or
- * reject if the time could not be increased.
- */
-export async function increaseTimeAndMineBlockAsync(seconds: number): Promise<number> {
- if (_.isUndefined(firstAccount)) {
- const accounts = await web3Wrapper.getAvailableAddressesAsync();
- firstAccount = accounts[0];
- }
-
- const offset = await web3Wrapper.increaseTimeAsync(seconds);
- // Note: we need to send a transaction after increasing time so
- // that a block is actually mined. The contract looks at the
- // last mined block for the timestamp.
- await web3Wrapper.awaitTransactionSuccessAsync(
- await web3Wrapper.sendTransactionAsync({ from: firstAccount, to: firstAccount, value: 0 }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
-
- return offset;
-}
-
-/**
- * Returns the timestamp of the latest block in seconds since the Unix epoch.
- * @returns a new Promise which will resolve with the timestamp in seconds.
- */
-export async function getLatestBlockTimestampAsync(): Promise<number> {
- const currentBlockIfExists = await web3Wrapper.getBlockIfExistsAsync('latest');
- if (_.isUndefined(currentBlockIfExists)) {
- throw new Error(`Unable to fetch latest block.`);
- }
- return currentBlockIfExists.timestamp;
-}
diff --git a/packages/contracts/test/utils/chai_setup.ts b/packages/contracts/test/utils/chai_setup.ts
deleted file mode 100644
index 1a8733093..000000000
--- a/packages/contracts/test/utils/chai_setup.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import * as chai from 'chai';
-import chaiAsPromised = require('chai-as-promised');
-import ChaiBigNumber = require('chai-bignumber');
-import * as dirtyChai from 'dirty-chai';
-
-export const chaiSetup = {
- configure(): void {
- chai.config.includeStack = true;
- chai.use(ChaiBigNumber());
- chai.use(dirtyChai);
- chai.use(chaiAsPromised);
- },
-};
diff --git a/packages/contracts/test/utils/combinatorial_utils.ts b/packages/contracts/test/utils/combinatorial_utils.ts
deleted file mode 100644
index bb1b55b4d..000000000
--- a/packages/contracts/test/utils/combinatorial_utils.ts
+++ /dev/null
@@ -1,113 +0,0 @@
-import { BigNumber } from '@0x/utils';
-import * as combinatorics from 'js-combinatorics';
-
-import { testWithReferenceFuncAsync } from './test_with_reference';
-
-// A set of values corresponding to the uint256 type in Solidity. This set
-// contains some notable edge cases, including some values which will overflow
-// the uint256 type when used in different mathematical operations.
-export const uint256Values = [
- new BigNumber(0),
- new BigNumber(1),
- new BigNumber(2),
- // Non-trivial big number.
- new BigNumber(2).pow(64),
- // Max that does not overflow when squared.
- new BigNumber(2).pow(128).minus(1),
- // Min that does overflow when squared.
- new BigNumber(2).pow(128),
- // Max that does not overflow when doubled.
- new BigNumber(2).pow(255).minus(1),
- // Min that does overflow when doubled.
- new BigNumber(2).pow(255),
- // Max that does not overflow.
- new BigNumber(2).pow(256).minus(1),
-];
-
-// A set of values corresponding to the bytes32 type in Solidity.
-export const bytes32Values = [
- // Min
- '0x0000000000000000000000000000000000000000000000000000000000000000',
- '0x0000000000000000000000000000000000000000000000000000000000000001',
- '0x0000000000000000000000000000000000000000000000000000000000000002',
- // Non-trivial big number.
- '0x000000000000f000000000000000000000000000000000000000000000000000',
- // Max
- '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
-];
-
-export async function testCombinatoriallyWithReferenceFuncAsync<P0, P1, R>(
- name: string,
- referenceFunc: (p0: P0, p1: P1) => Promise<R>,
- testFunc: (p0: P0, p1: P1) => Promise<R>,
- allValues: [P0[], P1[]],
-): Promise<void>;
-export async function testCombinatoriallyWithReferenceFuncAsync<P0, P1, P2, R>(
- name: string,
- referenceFunc: (p0: P0, p1: P1, p2: P2) => Promise<R>,
- testFunc: (p0: P0, p1: P1, p2: P2) => Promise<R>,
- allValues: [P0[], P1[], P2[]],
-): Promise<void>;
-export async function testCombinatoriallyWithReferenceFuncAsync<P0, P1, P2, P3, R>(
- name: string,
- referenceFunc: (p0: P0, p1: P1, p2: P2, p3: P3) => Promise<R>,
- testFunc: (p0: P0, p1: P1, p2: P2, p3: P3) => Promise<R>,
- allValues: [P0[], P1[], P2[], P3[]],
-): Promise<void>;
-export async function testCombinatoriallyWithReferenceFuncAsync<P0, P1, P2, P3, P4, R>(
- name: string,
- referenceFunc: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4) => Promise<R>,
- testFunc: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4) => Promise<R>,
- allValues: [P0[], P1[], P2[], P3[], P4[]],
-): Promise<void>;
-
-/**
- * Uses combinatorics to test the behavior of a test function by comparing it to
- * the expected behavior (defined by a reference function) for a large number of
- * possible input values.
- *
- * First generates test cases by taking the cartesian product of the given
- * values. Each test case is a set of N values corresponding to the N arguments
- * for the test func and the reference func. For each test case, first the
- * reference function will be called to obtain an "expected result", or if the
- * reference function throws/rejects, an "expected error". Next, the test
- * function will be called to obtain an "actual result", or if the test function
- * throws/rejects, an "actual error". Each test case passes if at least one of
- * the following conditions is met:
- *
- * 1) Neither the reference function or the test function throw and the
- * "expected result" equals the "actual result".
- *
- * 2) Both the reference function and the test function throw and the "actual
- * error" message *contains* the "expected error" message.
- *
- * The first test case which does not meet one of these conditions will cause
- * the entire test to fail and this function will throw/reject.
- *
- * @param referenceFuncAsync a reference function implemented in pure
- * JavaScript/TypeScript which accepts N arguments and returns the "expected
- * result" or "expected error" for a given test case.
- * @param testFuncAsync a test function which, e.g., makes a call or sends a
- * transaction to a contract. It accepts the same N arguments returns the
- * "actual result" or "actual error" for a given test case.
- * @param values an array of N arrays. Each inner array is a set of possible
- * values which are passed into both the reference function and the test
- * function.
- * @return A Promise that resolves if the test passes and rejects if the test
- * fails, according to the rules described above.
- */
-export async function testCombinatoriallyWithReferenceFuncAsync(
- name: string,
- referenceFuncAsync: (...args: any[]) => Promise<any>,
- testFuncAsync: (...args: any[]) => Promise<any>,
- allValues: any[],
-): Promise<void> {
- const testCases = combinatorics.cartesianProduct(...allValues);
- let counter = 0;
- testCases.forEach(async testCase => {
- counter += 1;
- it(`${name} ${counter}/${testCases.length}`, async () => {
- await testWithReferenceFuncAsync(referenceFuncAsync, testFuncAsync, testCase as any);
- });
- });
-}
diff --git a/packages/contracts/test/utils/constants.ts b/packages/contracts/test/utils/constants.ts
deleted file mode 100644
index d2c3ab512..000000000
--- a/packages/contracts/test/utils/constants.ts
+++ /dev/null
@@ -1,67 +0,0 @@
-import { BigNumber } from '@0x/utils';
-import { Web3Wrapper } from '@0x/web3-wrapper';
-import * as ethUtil from 'ethereumjs-util';
-import * as _ from 'lodash';
-
-const TESTRPC_PRIVATE_KEYS_STRINGS = [
- '0xf2f48ee19680706196e2e339e5da3491186e0c4c5030670656b0e0164837257d',
- '0x5d862464fe9303452126c8bc94274b8c5f9874cbd219789b3eb2128075a76f72',
- '0xdf02719c4df8b9b8ac7f551fcb5d9ef48fa27eef7a66453879f4d8fdc6e78fb1',
- '0xff12e391b79415e941a94de3bf3a9aee577aed0731e297d5cfa0b8a1e02fa1d0',
- '0x752dd9cf65e68cfaba7d60225cbdbc1f4729dd5e5507def72815ed0d8abc6249',
- '0xefb595a0178eb79a8df953f87c5148402a224cdf725e88c0146727c6aceadccd',
- '0x83c6d2cc5ddcf9711a6d59b417dc20eb48afd58d45290099e5987e3d768f328f',
- '0xbb2d3f7c9583780a7d3904a2f55d792707c345f21de1bacb2d389934d82796b2',
- '0xb2fd4d29c1390b71b8795ae81196bfd60293adf99f9d32a0aff06288fcdac55f',
- '0x23cb7121166b9a2f93ae0b7c05bde02eae50d64449b2cbb42bc84e9d38d6cc89',
-];
-
-export const constants = {
- BASE_16: 16,
- INVALID_OPCODE: 'invalid opcode',
- TESTRPC_NETWORK_ID: 50,
- // Note(albrow): In practice V8 and most other engines limit the minimum
- // interval for setInterval to 10ms. We still set it to 0 here in order to
- // ensure we always use the minimum interval.
- AWAIT_TRANSACTION_MINED_MS: 0,
- MAX_ETHERTOKEN_WITHDRAW_GAS: 43000,
- MAX_EXECUTE_TRANSACTION_GAS: 1000000,
- MAX_TOKEN_TRANSFERFROM_GAS: 80000,
- MAX_TOKEN_APPROVE_GAS: 60000,
- MAX_TRANSFER_FROM_GAS: 150000,
- DUMMY_TOKEN_NAME: '',
- DUMMY_TOKEN_SYMBOL: '',
- DUMMY_TOKEN_DECIMALS: new BigNumber(18),
- DUMMY_TOKEN_TOTAL_SUPPLY: new BigNumber(0),
- NULL_BYTES: '0x',
- NUM_DUMMY_ERC20_TO_DEPLOY: 3,
- NUM_DUMMY_ERC721_TO_DEPLOY: 2,
- NUM_ERC721_TOKENS_TO_MINT: 2,
- NULL_ADDRESS: '0x0000000000000000000000000000000000000000',
- UNLIMITED_ALLOWANCE_IN_BASE_UNITS: new BigNumber(2).pow(256).minus(1),
- TESTRPC_PRIVATE_KEYS: _.map(TESTRPC_PRIVATE_KEYS_STRINGS, privateKeyString => ethUtil.toBuffer(privateKeyString)),
- INITIAL_ERC20_BALANCE: Web3Wrapper.toBaseUnitAmount(new BigNumber(10000), 18),
- INITIAL_ERC20_ALLOWANCE: Web3Wrapper.toBaseUnitAmount(new BigNumber(10000), 18),
- STATIC_ORDER_PARAMS: {
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(200), 18),
- makerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 18),
- takerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 18),
- },
- WORD_LENGTH: 32,
- ZERO_AMOUNT: new BigNumber(0),
- PERCENTAGE_DENOMINATOR: new BigNumber(10).pow(18),
- FUNCTIONS_WITH_MUTEX: [
- 'FILL_ORDER',
- 'FILL_OR_KILL_ORDER',
- 'BATCH_FILL_ORDERS',
- 'BATCH_FILL_OR_KILL_ORDERS',
- 'MARKET_BUY_ORDERS',
- 'MARKET_SELL_ORDERS',
- 'MATCH_ORDERS',
- 'CANCEL_ORDER',
- 'BATCH_CANCEL_ORDERS',
- 'CANCEL_ORDERS_UP_TO',
- 'SET_SIGNATURE_VALIDATOR_APPROVAL',
- ],
-};
diff --git a/packages/contracts/test/utils/coverage.ts b/packages/contracts/test/utils/coverage.ts
deleted file mode 100644
index 5becfa1b6..000000000
--- a/packages/contracts/test/utils/coverage.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-import { devConstants } from '@0x/dev-utils';
-import { CoverageSubprovider, SolCompilerArtifactAdapter } from '@0x/sol-cov';
-import * as _ from 'lodash';
-
-let coverageSubprovider: CoverageSubprovider;
-
-export const coverage = {
- getCoverageSubproviderSingleton(): CoverageSubprovider {
- if (_.isUndefined(coverageSubprovider)) {
- coverageSubprovider = coverage._getCoverageSubprovider();
- }
- return coverageSubprovider;
- },
- _getCoverageSubprovider(): CoverageSubprovider {
- const defaultFromAddress = devConstants.TESTRPC_FIRST_ADDRESS;
- const solCompilerArtifactAdapter = new SolCompilerArtifactAdapter();
- const isVerbose = true;
- const subprovider = new CoverageSubprovider(solCompilerArtifactAdapter, defaultFromAddress, isVerbose);
- return subprovider;
- },
-};
diff --git a/packages/contracts/test/utils/erc20_wrapper.ts b/packages/contracts/test/utils/erc20_wrapper.ts
deleted file mode 100644
index c281a2abf..000000000
--- a/packages/contracts/test/utils/erc20_wrapper.ts
+++ /dev/null
@@ -1,182 +0,0 @@
-import { assetDataUtils } from '@0x/order-utils';
-import { BigNumber } from '@0x/utils';
-import { Web3Wrapper } from '@0x/web3-wrapper';
-import { Provider } from 'ethereum-types';
-import * as _ from 'lodash';
-
-import { DummyERC20TokenContract } from '../../generated-wrappers/dummy_erc20_token';
-import { ERC20ProxyContract } from '../../generated-wrappers/erc20_proxy';
-import { artifacts } from '../../src/artifacts';
-
-import { constants } from './constants';
-import { ERC20BalancesByOwner } from './types';
-import { txDefaults } from './web3_wrapper';
-
-export class ERC20Wrapper {
- private readonly _tokenOwnerAddresses: string[];
- private readonly _contractOwnerAddress: string;
- private readonly _web3Wrapper: Web3Wrapper;
- private readonly _provider: Provider;
- private readonly _dummyTokenContracts: DummyERC20TokenContract[];
- private _proxyContract?: ERC20ProxyContract;
- private _proxyIdIfExists?: string;
- /**
- * Instanitates an ERC20Wrapper
- * @param provider Web3 provider to use for all JSON RPC requests
- * @param tokenOwnerAddresses Addresses that we want to endow as owners for dummy ERC20 tokens
- * @param contractOwnerAddress Desired owner of the contract
- * Instance of ERC20Wrapper
- */
- constructor(provider: Provider, tokenOwnerAddresses: string[], contractOwnerAddress: string) {
- this._dummyTokenContracts = [];
- this._web3Wrapper = new Web3Wrapper(provider);
- this._provider = provider;
- this._tokenOwnerAddresses = tokenOwnerAddresses;
- this._contractOwnerAddress = contractOwnerAddress;
- }
- public async deployDummyTokensAsync(
- numberToDeploy: number,
- decimals: BigNumber,
- ): Promise<DummyERC20TokenContract[]> {
- for (let i = 0; i < numberToDeploy; i++) {
- this._dummyTokenContracts.push(
- await DummyERC20TokenContract.deployFrom0xArtifactAsync(
- artifacts.DummyERC20Token,
- this._provider,
- txDefaults,
- constants.DUMMY_TOKEN_NAME,
- constants.DUMMY_TOKEN_SYMBOL,
- decimals,
- constants.DUMMY_TOKEN_TOTAL_SUPPLY,
- ),
- );
- }
- return this._dummyTokenContracts;
- }
- public async deployProxyAsync(): Promise<ERC20ProxyContract> {
- this._proxyContract = await ERC20ProxyContract.deployFrom0xArtifactAsync(
- artifacts.ERC20Proxy,
- this._provider,
- txDefaults,
- );
- this._proxyIdIfExists = await this._proxyContract.getProxyId.callAsync();
- return this._proxyContract;
- }
- public getProxyId(): string {
- this._validateProxyContractExistsOrThrow();
- return this._proxyIdIfExists as string;
- }
- public async setBalancesAndAllowancesAsync(): Promise<void> {
- this._validateDummyTokenContractsExistOrThrow();
- this._validateProxyContractExistsOrThrow();
- for (const dummyTokenContract of this._dummyTokenContracts) {
- for (const tokenOwnerAddress of this._tokenOwnerAddresses) {
- await this._web3Wrapper.awaitTransactionSuccessAsync(
- await dummyTokenContract.setBalance.sendTransactionAsync(
- tokenOwnerAddress,
- constants.INITIAL_ERC20_BALANCE,
- { from: this._contractOwnerAddress },
- ),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await this._web3Wrapper.awaitTransactionSuccessAsync(
- await dummyTokenContract.approve.sendTransactionAsync(
- (this._proxyContract as ERC20ProxyContract).address,
- constants.INITIAL_ERC20_ALLOWANCE,
- { from: tokenOwnerAddress },
- ),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- }
- }
- }
- public async getBalanceAsync(userAddress: string, assetData: string): Promise<BigNumber> {
- const tokenContract = this._getTokenContractFromAssetData(assetData);
- const balance = new BigNumber(await tokenContract.balanceOf.callAsync(userAddress));
- return balance;
- }
- public async setBalanceAsync(userAddress: string, assetData: string, amount: BigNumber): Promise<void> {
- const tokenContract = this._getTokenContractFromAssetData(assetData);
- await this._web3Wrapper.awaitTransactionSuccessAsync(
- await tokenContract.setBalance.sendTransactionAsync(userAddress, amount, {
- from: this._contractOwnerAddress,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- }
- public async getProxyAllowanceAsync(userAddress: string, assetData: string): Promise<BigNumber> {
- const tokenContract = this._getTokenContractFromAssetData(assetData);
- const proxyAddress = (this._proxyContract as ERC20ProxyContract).address;
- const allowance = new BigNumber(await tokenContract.allowance.callAsync(userAddress, proxyAddress));
- return allowance;
- }
- public async setAllowanceAsync(userAddress: string, assetData: string, amount: BigNumber): Promise<void> {
- const tokenContract = this._getTokenContractFromAssetData(assetData);
- const proxyAddress = (this._proxyContract as ERC20ProxyContract).address;
- await this._web3Wrapper.awaitTransactionSuccessAsync(
- await tokenContract.approve.sendTransactionAsync(proxyAddress, amount, {
- from: userAddress,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- }
- public async getBalancesAsync(): Promise<ERC20BalancesByOwner> {
- this._validateDummyTokenContractsExistOrThrow();
- const balancesByOwner: ERC20BalancesByOwner = {};
- const balances: BigNumber[] = [];
- const balanceInfo: Array<{ tokenOwnerAddress: string; tokenAddress: string }> = [];
- for (const dummyTokenContract of this._dummyTokenContracts) {
- for (const tokenOwnerAddress of this._tokenOwnerAddresses) {
- balances.push(await dummyTokenContract.balanceOf.callAsync(tokenOwnerAddress));
- balanceInfo.push({
- tokenOwnerAddress,
- tokenAddress: dummyTokenContract.address,
- });
- }
- }
- _.forEach(balances, (balance, balanceIndex) => {
- const tokenAddress = balanceInfo[balanceIndex].tokenAddress;
- const tokenOwnerAddress = balanceInfo[balanceIndex].tokenOwnerAddress;
- if (_.isUndefined(balancesByOwner[tokenOwnerAddress])) {
- balancesByOwner[tokenOwnerAddress] = {};
- }
- const wrappedBalance = new BigNumber(balance);
- balancesByOwner[tokenOwnerAddress][tokenAddress] = wrappedBalance;
- });
- return balancesByOwner;
- }
- public addDummyTokenContract(dummy: DummyERC20TokenContract): void {
- if (!_.isUndefined(this._dummyTokenContracts)) {
- this._dummyTokenContracts.push(dummy);
- }
- }
- public addTokenOwnerAddress(address: string): void {
- this._tokenOwnerAddresses.push(address);
- }
- public getTokenOwnerAddresses(): string[] {
- return this._tokenOwnerAddresses;
- }
- public getTokenAddresses(): string[] {
- const tokenAddresses = _.map(this._dummyTokenContracts, dummyTokenContract => dummyTokenContract.address);
- return tokenAddresses;
- }
- private _getTokenContractFromAssetData(assetData: string): DummyERC20TokenContract {
- const erc20ProxyData = assetDataUtils.decodeERC20AssetData(assetData);
- const tokenAddress = erc20ProxyData.tokenAddress;
- const tokenContractIfExists = _.find(this._dummyTokenContracts, c => c.address === tokenAddress);
- if (_.isUndefined(tokenContractIfExists)) {
- throw new Error(`Token: ${tokenAddress} was not deployed through ERC20Wrapper`);
- }
- return tokenContractIfExists;
- }
- private _validateDummyTokenContractsExistOrThrow(): void {
- if (_.isUndefined(this._dummyTokenContracts)) {
- throw new Error('Dummy ERC20 tokens not yet deployed, please call "deployDummyTokensAsync"');
- }
- }
- private _validateProxyContractExistsOrThrow(): void {
- if (_.isUndefined(this._proxyContract)) {
- throw new Error('ERC20 proxy contract not yet deployed, please call "deployProxyAsync"');
- }
- }
-}
diff --git a/packages/contracts/test/utils/erc721_wrapper.ts b/packages/contracts/test/utils/erc721_wrapper.ts
deleted file mode 100644
index e9da553d0..000000000
--- a/packages/contracts/test/utils/erc721_wrapper.ts
+++ /dev/null
@@ -1,239 +0,0 @@
-import { generatePseudoRandomSalt } from '@0x/order-utils';
-import { BigNumber } from '@0x/utils';
-import { Web3Wrapper } from '@0x/web3-wrapper';
-import { Provider } from 'ethereum-types';
-import * as _ from 'lodash';
-
-import { DummyERC721TokenContract } from '../../generated-wrappers/dummy_erc721_token';
-import { ERC721ProxyContract } from '../../generated-wrappers/erc721_proxy';
-import { artifacts } from '../../src/artifacts';
-
-import { constants } from './constants';
-import { ERC721TokenIdsByOwner } from './types';
-import { txDefaults } from './web3_wrapper';
-
-export class ERC721Wrapper {
- private readonly _tokenOwnerAddresses: string[];
- private readonly _contractOwnerAddress: string;
- private readonly _web3Wrapper: Web3Wrapper;
- private readonly _provider: Provider;
- private readonly _dummyTokenContracts: DummyERC721TokenContract[];
- private _proxyContract?: ERC721ProxyContract;
- private _proxyIdIfExists?: string;
- private _initialTokenIdsByOwner: ERC721TokenIdsByOwner = {};
- constructor(provider: Provider, tokenOwnerAddresses: string[], contractOwnerAddress: string) {
- this._web3Wrapper = new Web3Wrapper(provider);
- this._provider = provider;
- this._dummyTokenContracts = [];
- this._tokenOwnerAddresses = tokenOwnerAddresses;
- this._contractOwnerAddress = contractOwnerAddress;
- }
- public async deployDummyTokensAsync(): Promise<DummyERC721TokenContract[]> {
- // tslint:disable-next-line:no-unused-variable
- for (const i of _.times(constants.NUM_DUMMY_ERC721_TO_DEPLOY)) {
- this._dummyTokenContracts.push(
- await DummyERC721TokenContract.deployFrom0xArtifactAsync(
- artifacts.DummyERC721Token,
- this._provider,
- txDefaults,
- constants.DUMMY_TOKEN_NAME,
- constants.DUMMY_TOKEN_SYMBOL,
- ),
- );
- }
- return this._dummyTokenContracts;
- }
- public async deployProxyAsync(): Promise<ERC721ProxyContract> {
- this._proxyContract = await ERC721ProxyContract.deployFrom0xArtifactAsync(
- artifacts.ERC721Proxy,
- this._provider,
- txDefaults,
- );
- this._proxyIdIfExists = await this._proxyContract.getProxyId.callAsync();
- return this._proxyContract;
- }
- public getProxyId(): string {
- this._validateProxyContractExistsOrThrow();
- return this._proxyIdIfExists as string;
- }
- public async setBalancesAndAllowancesAsync(): Promise<void> {
- this._validateDummyTokenContractsExistOrThrow();
- this._validateProxyContractExistsOrThrow();
- this._initialTokenIdsByOwner = {};
- for (const dummyTokenContract of this._dummyTokenContracts) {
- for (const tokenOwnerAddress of this._tokenOwnerAddresses) {
- // tslint:disable-next-line:no-unused-variable
- for (const i of _.times(constants.NUM_ERC721_TOKENS_TO_MINT)) {
- const tokenId = generatePseudoRandomSalt();
- await this.mintAsync(dummyTokenContract.address, tokenId, tokenOwnerAddress);
- if (_.isUndefined(this._initialTokenIdsByOwner[tokenOwnerAddress])) {
- this._initialTokenIdsByOwner[tokenOwnerAddress] = {
- [dummyTokenContract.address]: [],
- };
- }
- if (_.isUndefined(this._initialTokenIdsByOwner[tokenOwnerAddress][dummyTokenContract.address])) {
- this._initialTokenIdsByOwner[tokenOwnerAddress][dummyTokenContract.address] = [];
- }
- this._initialTokenIdsByOwner[tokenOwnerAddress][dummyTokenContract.address].push(tokenId);
-
- await this.approveProxyAsync(dummyTokenContract.address, tokenId);
- }
- }
- }
- }
- public async doesTokenExistAsync(tokenAddress: string, tokenId: BigNumber): Promise<boolean> {
- const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
- const owner = await tokenContract.ownerOf.callAsync(tokenId);
- const doesExist = owner !== constants.NULL_ADDRESS;
- return doesExist;
- }
- public async approveProxyAsync(tokenAddress: string, tokenId: BigNumber): Promise<void> {
- const proxyAddress = (this._proxyContract as ERC721ProxyContract).address;
- await this.approveAsync(proxyAddress, tokenAddress, tokenId);
- }
- public async approveProxyForAllAsync(tokenAddress: string, tokenId: BigNumber, isApproved: boolean): Promise<void> {
- const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
- const tokenOwner = await this.ownerOfAsync(tokenAddress, tokenId);
- const proxyAddress = (this._proxyContract as ERC721ProxyContract).address;
- await this._web3Wrapper.awaitTransactionSuccessAsync(
- await tokenContract.setApprovalForAll.sendTransactionAsync(proxyAddress, isApproved, {
- from: tokenOwner,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- }
- public async approveAsync(to: string, tokenAddress: string, tokenId: BigNumber): Promise<void> {
- const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
- const tokenOwner = await this.ownerOfAsync(tokenAddress, tokenId);
- await this._web3Wrapper.awaitTransactionSuccessAsync(
- await tokenContract.approve.sendTransactionAsync(to, tokenId, {
- from: tokenOwner,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- }
- public async transferFromAsync(
- tokenAddress: string,
- tokenId: BigNumber,
- currentOwner: string,
- userAddress: string,
- ): Promise<void> {
- const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
- await this._web3Wrapper.awaitTransactionSuccessAsync(
- await tokenContract.transferFrom.sendTransactionAsync(currentOwner, userAddress, tokenId, {
- from: currentOwner,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- }
- public async mintAsync(tokenAddress: string, tokenId: BigNumber, userAddress: string): Promise<void> {
- const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
- await this._web3Wrapper.awaitTransactionSuccessAsync(
- await tokenContract.mint.sendTransactionAsync(userAddress, tokenId, {
- from: this._contractOwnerAddress,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- }
- public async burnAsync(tokenAddress: string, tokenId: BigNumber, owner: string): Promise<void> {
- const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
- await this._web3Wrapper.awaitTransactionSuccessAsync(
- await tokenContract.burn.sendTransactionAsync(owner, tokenId, {
- from: this._contractOwnerAddress,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- }
- public async ownerOfAsync(tokenAddress: string, tokenId: BigNumber): Promise<string> {
- const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
- const owner = await tokenContract.ownerOf.callAsync(tokenId);
- return owner;
- }
- public async isOwnerAsync(userAddress: string, tokenAddress: string, tokenId: BigNumber): Promise<boolean> {
- const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
- const tokenOwner = await tokenContract.ownerOf.callAsync(tokenId);
- const isOwner = tokenOwner === userAddress;
- return isOwner;
- }
- public async isProxyApprovedForAllAsync(userAddress: string, tokenAddress: string): Promise<boolean> {
- this._validateProxyContractExistsOrThrow();
- const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
- const operator = (this._proxyContract as ERC721ProxyContract).address;
- const didApproveAll = await tokenContract.isApprovedForAll.callAsync(userAddress, operator);
- return didApproveAll;
- }
- public async isProxyApprovedAsync(tokenAddress: string, tokenId: BigNumber): Promise<boolean> {
- this._validateProxyContractExistsOrThrow();
- const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
- const approvedAddress = await tokenContract.getApproved.callAsync(tokenId);
- const proxyAddress = (this._proxyContract as ERC721ProxyContract).address;
- const isProxyAnApprovedOperator = approvedAddress === proxyAddress;
- return isProxyAnApprovedOperator;
- }
- public async getBalancesAsync(): Promise<ERC721TokenIdsByOwner> {
- this._validateDummyTokenContractsExistOrThrow();
- this._validateBalancesAndAllowancesSetOrThrow();
- const tokenIdsByOwner: ERC721TokenIdsByOwner = {};
- const tokenOwnerAddresses: string[] = [];
- const tokenInfo: Array<{ tokenId: BigNumber; tokenAddress: string }> = [];
- for (const dummyTokenContract of this._dummyTokenContracts) {
- for (const tokenOwnerAddress of this._tokenOwnerAddresses) {
- const initialTokenOwnerIds = this._initialTokenIdsByOwner[tokenOwnerAddress][
- dummyTokenContract.address
- ];
- for (const tokenId of initialTokenOwnerIds) {
- tokenOwnerAddresses.push(await dummyTokenContract.ownerOf.callAsync(tokenId));
- tokenInfo.push({
- tokenId,
- tokenAddress: dummyTokenContract.address,
- });
- }
- }
- }
- _.forEach(tokenOwnerAddresses, (tokenOwnerAddress, ownerIndex) => {
- const tokenAddress = tokenInfo[ownerIndex].tokenAddress;
- const tokenId = tokenInfo[ownerIndex].tokenId;
- if (_.isUndefined(tokenIdsByOwner[tokenOwnerAddress])) {
- tokenIdsByOwner[tokenOwnerAddress] = {
- [tokenAddress]: [],
- };
- }
- if (_.isUndefined(tokenIdsByOwner[tokenOwnerAddress][tokenAddress])) {
- tokenIdsByOwner[tokenOwnerAddress][tokenAddress] = [];
- }
- tokenIdsByOwner[tokenOwnerAddress][tokenAddress].push(tokenId);
- });
- return tokenIdsByOwner;
- }
- public getTokenOwnerAddresses(): string[] {
- return this._tokenOwnerAddresses;
- }
- public getTokenAddresses(): string[] {
- const tokenAddresses = _.map(this._dummyTokenContracts, dummyTokenContract => dummyTokenContract.address);
- return tokenAddresses;
- }
- private _getTokenContractFromAssetData(tokenAddress: string): DummyERC721TokenContract {
- const tokenContractIfExists = _.find(this._dummyTokenContracts, c => c.address === tokenAddress);
- if (_.isUndefined(tokenContractIfExists)) {
- throw new Error(`Token: ${tokenAddress} was not deployed through ERC20Wrapper`);
- }
- return tokenContractIfExists;
- }
- private _validateDummyTokenContractsExistOrThrow(): void {
- if (_.isUndefined(this._dummyTokenContracts)) {
- throw new Error('Dummy ERC721 tokens not yet deployed, please call "deployDummyTokensAsync"');
- }
- }
- private _validateProxyContractExistsOrThrow(): void {
- if (_.isUndefined(this._proxyContract)) {
- throw new Error('ERC721 proxy contract not yet deployed, please call "deployProxyAsync"');
- }
- }
- private _validateBalancesAndAllowancesSetOrThrow(): void {
- if (_.keys(this._initialTokenIdsByOwner).length === 0) {
- throw new Error(
- 'Dummy ERC721 balances and allowances not yet set, please call "setBalancesAndAllowancesAsync"',
- );
- }
- }
-}
diff --git a/packages/contracts/test/utils/exchange_wrapper.ts b/packages/contracts/test/utils/exchange_wrapper.ts
deleted file mode 100644
index c28989d3f..000000000
--- a/packages/contracts/test/utils/exchange_wrapper.ts
+++ /dev/null
@@ -1,276 +0,0 @@
-import { SignedOrder } from '@0x/types';
-import { BigNumber } from '@0x/utils';
-import { Web3Wrapper } from '@0x/web3-wrapper';
-import { Provider, TransactionReceiptWithDecodedLogs } from 'ethereum-types';
-
-import { ExchangeContract } from '../../generated-wrappers/exchange';
-
-import { formatters } from './formatters';
-import { LogDecoder } from './log_decoder';
-import { orderUtils } from './order_utils';
-import { FillResults, OrderInfo, SignedTransaction } from './types';
-
-export class ExchangeWrapper {
- private readonly _exchange: ExchangeContract;
- private readonly _web3Wrapper: Web3Wrapper;
- private readonly _logDecoder: LogDecoder;
- constructor(exchangeContract: ExchangeContract, provider: Provider) {
- this._exchange = exchangeContract;
- this._web3Wrapper = new Web3Wrapper(provider);
- this._logDecoder = new LogDecoder(this._web3Wrapper);
- }
- public async fillOrderAsync(
- signedOrder: SignedOrder,
- from: string,
- opts: { takerAssetFillAmount?: BigNumber } = {},
- ): Promise<TransactionReceiptWithDecodedLogs> {
- const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount);
- const txHash = await this._exchange.fillOrder.sendTransactionAsync(
- params.order,
- params.takerAssetFillAmount,
- params.signature,
- { from },
- );
- const txReceipt = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
- return txReceipt;
- }
- public async cancelOrderAsync(signedOrder: SignedOrder, from: string): Promise<TransactionReceiptWithDecodedLogs> {
- const params = orderUtils.createCancel(signedOrder);
- const txHash = await this._exchange.cancelOrder.sendTransactionAsync(params.order, { from });
- const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
- return tx;
- }
- public async fillOrKillOrderAsync(
- signedOrder: SignedOrder,
- from: string,
- opts: { takerAssetFillAmount?: BigNumber } = {},
- ): Promise<TransactionReceiptWithDecodedLogs> {
- const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount);
- const txHash = await this._exchange.fillOrKillOrder.sendTransactionAsync(
- params.order,
- params.takerAssetFillAmount,
- params.signature,
- { from },
- );
- const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
- return tx;
- }
- public async fillOrderNoThrowAsync(
- signedOrder: SignedOrder,
- from: string,
- opts: { takerAssetFillAmount?: BigNumber; gas?: number } = {},
- ): Promise<TransactionReceiptWithDecodedLogs> {
- const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount);
- const txHash = await this._exchange.fillOrderNoThrow.sendTransactionAsync(
- params.order,
- params.takerAssetFillAmount,
- params.signature,
- { from, gas: opts.gas },
- );
- const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
- return tx;
- }
- public async batchFillOrdersAsync(
- orders: SignedOrder[],
- from: string,
- opts: { takerAssetFillAmounts?: BigNumber[] } = {},
- ): Promise<TransactionReceiptWithDecodedLogs> {
- const params = formatters.createBatchFill(orders, opts.takerAssetFillAmounts);
- const txHash = await this._exchange.batchFillOrders.sendTransactionAsync(
- params.orders,
- params.takerAssetFillAmounts,
- params.signatures,
- { from },
- );
- const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
- return tx;
- }
- public async batchFillOrKillOrdersAsync(
- orders: SignedOrder[],
- from: string,
- opts: { takerAssetFillAmounts?: BigNumber[] } = {},
- ): Promise<TransactionReceiptWithDecodedLogs> {
- const params = formatters.createBatchFill(orders, opts.takerAssetFillAmounts);
- const txHash = await this._exchange.batchFillOrKillOrders.sendTransactionAsync(
- params.orders,
- params.takerAssetFillAmounts,
- params.signatures,
- { from },
- );
- const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
- return tx;
- }
- public async batchFillOrdersNoThrowAsync(
- orders: SignedOrder[],
- from: string,
- opts: { takerAssetFillAmounts?: BigNumber[]; gas?: number } = {},
- ): Promise<TransactionReceiptWithDecodedLogs> {
- const params = formatters.createBatchFill(orders, opts.takerAssetFillAmounts);
- const txHash = await this._exchange.batchFillOrdersNoThrow.sendTransactionAsync(
- params.orders,
- params.takerAssetFillAmounts,
- params.signatures,
- { from, gas: opts.gas },
- );
- const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
- return tx;
- }
- public async marketSellOrdersAsync(
- orders: SignedOrder[],
- from: string,
- opts: { takerAssetFillAmount: BigNumber },
- ): Promise<TransactionReceiptWithDecodedLogs> {
- const params = formatters.createMarketSellOrders(orders, opts.takerAssetFillAmount);
- const txHash = await this._exchange.marketSellOrders.sendTransactionAsync(
- params.orders,
- params.takerAssetFillAmount,
- params.signatures,
- { from },
- );
- const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
- return tx;
- }
- public async marketSellOrdersNoThrowAsync(
- orders: SignedOrder[],
- from: string,
- opts: { takerAssetFillAmount: BigNumber; gas?: number },
- ): Promise<TransactionReceiptWithDecodedLogs> {
- const params = formatters.createMarketSellOrders(orders, opts.takerAssetFillAmount);
- const txHash = await this._exchange.marketSellOrdersNoThrow.sendTransactionAsync(
- params.orders,
- params.takerAssetFillAmount,
- params.signatures,
- { from, gas: opts.gas },
- );
- const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
- return tx;
- }
- public async marketBuyOrdersAsync(
- orders: SignedOrder[],
- from: string,
- opts: { makerAssetFillAmount: BigNumber },
- ): Promise<TransactionReceiptWithDecodedLogs> {
- const params = formatters.createMarketBuyOrders(orders, opts.makerAssetFillAmount);
- const txHash = await this._exchange.marketBuyOrders.sendTransactionAsync(
- params.orders,
- params.makerAssetFillAmount,
- params.signatures,
- { from },
- );
- const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
- return tx;
- }
- public async marketBuyOrdersNoThrowAsync(
- orders: SignedOrder[],
- from: string,
- opts: { makerAssetFillAmount: BigNumber; gas?: number },
- ): Promise<TransactionReceiptWithDecodedLogs> {
- const params = formatters.createMarketBuyOrders(orders, opts.makerAssetFillAmount);
- const txHash = await this._exchange.marketBuyOrdersNoThrow.sendTransactionAsync(
- params.orders,
- params.makerAssetFillAmount,
- params.signatures,
- { from, gas: opts.gas },
- );
- const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
- return tx;
- }
- public async batchCancelOrdersAsync(
- orders: SignedOrder[],
- from: string,
- ): Promise<TransactionReceiptWithDecodedLogs> {
- const params = formatters.createBatchCancel(orders);
- const txHash = await this._exchange.batchCancelOrders.sendTransactionAsync(params.orders, { from });
- const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
- return tx;
- }
- public async cancelOrdersUpToAsync(salt: BigNumber, from: string): Promise<TransactionReceiptWithDecodedLogs> {
- const txHash = await this._exchange.cancelOrdersUpTo.sendTransactionAsync(salt, { from });
- const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
- return tx;
- }
- public async registerAssetProxyAsync(
- assetProxyAddress: string,
- from: string,
- ): Promise<TransactionReceiptWithDecodedLogs> {
- const txHash = await this._exchange.registerAssetProxy.sendTransactionAsync(assetProxyAddress, { from });
- const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
- return tx;
- }
- public async executeTransactionAsync(
- signedTx: SignedTransaction,
- from: string,
- ): Promise<TransactionReceiptWithDecodedLogs> {
- const txHash = await this._exchange.executeTransaction.sendTransactionAsync(
- signedTx.salt,
- signedTx.signerAddress,
- signedTx.data,
- signedTx.signature,
- { from },
- );
- const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
- return tx;
- }
- 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)) as OrderInfo;
- 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 txHash = await this._exchange.matchOrders.sendTransactionAsync(
- params.left,
- params.right,
- params.leftSignature,
- params.rightSignature,
- { from },
- );
- const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
- return tx;
- }
- 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 getExchangeAddress(): string {
- return this._exchange.address;
- }
-}
diff --git a/packages/contracts/test/utils/fill_order_combinatorial_utils.ts b/packages/contracts/test/utils/fill_order_combinatorial_utils.ts
deleted file mode 100644
index 8046771f9..000000000
--- a/packages/contracts/test/utils/fill_order_combinatorial_utils.ts
+++ /dev/null
@@ -1,924 +0,0 @@
-import {
- assetDataUtils,
- BalanceAndProxyAllowanceLazyStore,
- ExchangeTransferSimulator,
- orderHashUtils,
- OrderStateUtils,
- OrderValidationUtils,
-} from '@0x/order-utils';
-import { AssetProxyId, RevertReason, SignatureType, SignedOrder } from '@0x/types';
-import { BigNumber, errorUtils, logUtils } from '@0x/utils';
-import { Web3Wrapper } from '@0x/web3-wrapper';
-import * as chai from 'chai';
-import { LogWithDecodedArgs, Provider, TxData } from 'ethereum-types';
-import * as _ from 'lodash';
-import 'make-promises-safe';
-
-import { ExchangeContract, ExchangeFillEventArgs } from '../../generated-wrappers/exchange';
-import { TestLibsContract } from '../../generated-wrappers/test_libs';
-import { artifacts } from '../../src/artifacts';
-
-import { expectTransactionFailedAsync } from './assertions';
-import { AssetWrapper } from './asset_wrapper';
-import { chaiSetup } from './chai_setup';
-import { constants } from './constants';
-import { ERC20Wrapper } from './erc20_wrapper';
-import { ERC721Wrapper } from './erc721_wrapper';
-import { ExchangeWrapper } from './exchange_wrapper';
-import { OrderFactoryFromScenario } from './order_factory_from_scenario';
-import { orderUtils } from './order_utils';
-import { signingUtils } from './signing_utils';
-import { SimpleAssetBalanceAndProxyAllowanceFetcher } from './simple_asset_balance_and_proxy_allowance_fetcher';
-import { SimpleOrderFilledCancelledFetcher } from './simple_order_filled_cancelled_fetcher';
-import {
- AllowanceAmountScenario,
- AssetDataScenario,
- BalanceAmountScenario,
- ExpirationTimeSecondsScenario,
- FeeRecipientAddressScenario,
- FillScenario,
- OrderAssetAmountScenario,
- TakerAssetFillAmountScenario,
- TakerScenario,
- TraderStateScenario,
-} from './types';
-
-chaiSetup.configure();
-const expect = chai.expect;
-
-/**
- * Instantiates a new instance of FillOrderCombinatorialUtils. Since this method has some
- * required async setup, a factory method is required.
- * @param web3Wrapper Web3Wrapper instance
- * @param txDefaults Default Ethereum tx options
- * @return FillOrderCombinatorialUtils instance
- */
-export async function fillOrderCombinatorialUtilsFactoryAsync(
- web3Wrapper: Web3Wrapper,
- txDefaults: Partial<TxData>,
-): Promise<FillOrderCombinatorialUtils> {
- const accounts = await web3Wrapper.getAvailableAddressesAsync();
- const userAddresses = _.slice(accounts, 0, 5);
- const [ownerAddress, makerAddress, takerAddress] = userAddresses;
- const makerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[userAddresses.indexOf(makerAddress)];
-
- const provider = web3Wrapper.getProvider();
- const erc20Wrapper = new ERC20Wrapper(provider, userAddresses, ownerAddress);
- const erc721Wrapper = new ERC721Wrapper(provider, userAddresses, ownerAddress);
-
- const erc20EighteenDecimalTokenCount = 3;
- const eighteenDecimals = new BigNumber(18);
- const [
- erc20EighteenDecimalTokenA,
- erc20EighteenDecimalTokenB,
- zrxToken,
- ] = await erc20Wrapper.deployDummyTokensAsync(erc20EighteenDecimalTokenCount, eighteenDecimals);
- const zrxAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address);
-
- const erc20FiveDecimalTokenCount = 2;
- const fiveDecimals = new BigNumber(5);
- const [erc20FiveDecimalTokenA, erc20FiveDecimalTokenB] = await erc20Wrapper.deployDummyTokensAsync(
- erc20FiveDecimalTokenCount,
- fiveDecimals,
- );
- const zeroDecimals = new BigNumber(0);
- const erc20ZeroDecimalTokenCount = 2;
- const [erc20ZeroDecimalTokenA, erc20ZeroDecimalTokenB] = await erc20Wrapper.deployDummyTokensAsync(
- erc20ZeroDecimalTokenCount,
- zeroDecimals,
- );
- const erc20Proxy = await erc20Wrapper.deployProxyAsync();
- await erc20Wrapper.setBalancesAndAllowancesAsync();
-
- const [erc721Token] = await erc721Wrapper.deployDummyTokensAsync();
- const erc721Proxy = await erc721Wrapper.deployProxyAsync();
- await erc721Wrapper.setBalancesAndAllowancesAsync();
- const erc721Balances = await erc721Wrapper.getBalancesAsync();
-
- const assetWrapper = new AssetWrapper([erc20Wrapper, erc721Wrapper]);
-
- const exchangeContract = await ExchangeContract.deployFrom0xArtifactAsync(
- artifacts.Exchange,
- provider,
- txDefaults,
- zrxAssetData,
- );
- const exchangeWrapper = new ExchangeWrapper(exchangeContract, provider);
- await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, ownerAddress);
- await exchangeWrapper.registerAssetProxyAsync(erc721Proxy.address, ownerAddress);
-
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc20Proxy.addAuthorizedAddress.sendTransactionAsync(exchangeContract.address, {
- from: ownerAddress,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc721Proxy.addAuthorizedAddress.sendTransactionAsync(exchangeContract.address, {
- from: ownerAddress,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
-
- const orderFactory = new OrderFactoryFromScenario(
- userAddresses,
- zrxToken.address,
- [erc20EighteenDecimalTokenA.address, erc20EighteenDecimalTokenB.address],
- [erc20FiveDecimalTokenA.address, erc20FiveDecimalTokenB.address],
- [erc20ZeroDecimalTokenA.address, erc20ZeroDecimalTokenB.address],
- erc721Token,
- erc721Balances,
- exchangeContract.address,
- );
-
- const testLibsContract = await TestLibsContract.deployFrom0xArtifactAsync(artifacts.TestLibs, provider, txDefaults);
-
- const fillOrderCombinatorialUtils = new FillOrderCombinatorialUtils(
- orderFactory,
- ownerAddress,
- makerAddress,
- makerPrivateKey,
- takerAddress,
- zrxAssetData,
- exchangeWrapper,
- assetWrapper,
- testLibsContract,
- );
- return fillOrderCombinatorialUtils;
-}
-
-export class FillOrderCombinatorialUtils {
- public orderFactory: OrderFactoryFromScenario;
- public ownerAddress: string;
- public makerAddress: string;
- public makerPrivateKey: Buffer;
- public takerAddress: string;
- public zrxAssetData: string;
- public exchangeWrapper: ExchangeWrapper;
- public assetWrapper: AssetWrapper;
- public testLibsContract: TestLibsContract;
- public static generateFillOrderCombinations(): FillScenario[] {
- const takerScenarios = [
- TakerScenario.Unspecified,
- // TakerScenario.CorrectlySpecified,
- // TakerScenario.IncorrectlySpecified,
- ];
- const feeRecipientScenarios = [
- FeeRecipientAddressScenario.EthUserAddress,
- // FeeRecipientAddressScenario.BurnAddress,
- ];
- const makerAssetAmountScenario = [
- OrderAssetAmountScenario.Large,
- // OrderAssetAmountScenario.Zero,
- // OrderAssetAmountScenario.Small,
- ];
- const takerAssetAmountScenario = [
- OrderAssetAmountScenario.Large,
- // OrderAssetAmountScenario.Zero,
- // OrderAssetAmountScenario.Small,
- ];
- const makerFeeScenario = [
- OrderAssetAmountScenario.Large,
- // OrderAssetAmountScenario.Small,
- // OrderAssetAmountScenario.Zero,
- ];
- const takerFeeScenario = [
- OrderAssetAmountScenario.Large,
- // OrderAssetAmountScenario.Small,
- // OrderAssetAmountScenario.Zero,
- ];
- const expirationTimeSecondsScenario = [
- ExpirationTimeSecondsScenario.InFuture,
- ExpirationTimeSecondsScenario.InPast,
- ];
- const makerAssetDataScenario = [
- AssetDataScenario.ERC20FiveDecimals,
- AssetDataScenario.ERC20NonZRXEighteenDecimals,
- AssetDataScenario.ERC721,
- AssetDataScenario.ZRXFeeToken,
- ];
- const takerAssetDataScenario = [
- AssetDataScenario.ERC20FiveDecimals,
- AssetDataScenario.ERC20NonZRXEighteenDecimals,
- AssetDataScenario.ERC721,
- AssetDataScenario.ZRXFeeToken,
- ];
- const takerAssetFillAmountScenario = [
- TakerAssetFillAmountScenario.ExactlyRemainingFillableTakerAssetAmount,
- // TakerAssetFillAmountScenario.GreaterThanRemainingFillableTakerAssetAmount,
- // TakerAssetFillAmountScenario.LessThanRemainingFillableTakerAssetAmount,
- ];
- const makerAssetBalanceScenario = [
- BalanceAmountScenario.Higher,
- // BalanceAmountScenario.Exact,
- // BalanceAmountScenario.TooLow,
- ];
- const makerAssetAllowanceScenario = [
- AllowanceAmountScenario.Higher,
- // AllowanceAmountScenario.Exact,
- // AllowanceAmountScenario.TooLow,
- // AllowanceAmountScenario.Unlimited,
- ];
- const makerZRXBalanceScenario = [
- BalanceAmountScenario.Higher,
- // BalanceAmountScenario.Exact,
- // BalanceAmountScenario.TooLow,
- ];
- const makerZRXAllowanceScenario = [
- AllowanceAmountScenario.Higher,
- // AllowanceAmountScenario.Exact,
- // AllowanceAmountScenario.TooLow,
- // AllowanceAmountScenario.Unlimited,
- ];
- const takerAssetBalanceScenario = [
- BalanceAmountScenario.Higher,
- // BalanceAmountScenario.Exact,
- // BalanceAmountScenario.TooLow,
- ];
- const takerAssetAllowanceScenario = [
- AllowanceAmountScenario.Higher,
- // AllowanceAmountScenario.Exact,
- // AllowanceAmountScenario.TooLow,
- // AllowanceAmountScenario.Unlimited,
- ];
- const takerZRXBalanceScenario = [
- BalanceAmountScenario.Higher,
- // BalanceAmountScenario.Exact,
- // BalanceAmountScenario.TooLow,
- ];
- const takerZRXAllowanceScenario = [
- AllowanceAmountScenario.Higher,
- // AllowanceAmountScenario.Exact,
- // AllowanceAmountScenario.TooLow,
- // AllowanceAmountScenario.Unlimited,
- ];
- const fillScenarioArrays = FillOrderCombinatorialUtils._getAllCombinations([
- takerScenarios,
- feeRecipientScenarios,
- makerAssetAmountScenario,
- takerAssetAmountScenario,
- makerFeeScenario,
- takerFeeScenario,
- expirationTimeSecondsScenario,
- makerAssetDataScenario,
- takerAssetDataScenario,
- takerAssetFillAmountScenario,
- makerAssetBalanceScenario,
- makerAssetAllowanceScenario,
- makerZRXBalanceScenario,
- makerZRXAllowanceScenario,
- takerAssetBalanceScenario,
- takerAssetAllowanceScenario,
- takerZRXBalanceScenario,
- takerZRXAllowanceScenario,
- ]);
-
- const fillScenarios = _.map(fillScenarioArrays, fillScenarioArray => {
- // tslint:disable:custom-no-magic-numbers
- const fillScenario: FillScenario = {
- orderScenario: {
- takerScenario: fillScenarioArray[0] as TakerScenario,
- feeRecipientScenario: fillScenarioArray[1] as FeeRecipientAddressScenario,
- makerAssetAmountScenario: fillScenarioArray[2] as OrderAssetAmountScenario,
- takerAssetAmountScenario: fillScenarioArray[3] as OrderAssetAmountScenario,
- makerFeeScenario: fillScenarioArray[4] as OrderAssetAmountScenario,
- takerFeeScenario: fillScenarioArray[5] as OrderAssetAmountScenario,
- expirationTimeSecondsScenario: fillScenarioArray[6] as ExpirationTimeSecondsScenario,
- makerAssetDataScenario: fillScenarioArray[7] as AssetDataScenario,
- takerAssetDataScenario: fillScenarioArray[8] as AssetDataScenario,
- },
- takerAssetFillAmountScenario: fillScenarioArray[9] as TakerAssetFillAmountScenario,
- makerStateScenario: {
- traderAssetBalance: fillScenarioArray[10] as BalanceAmountScenario,
- traderAssetAllowance: fillScenarioArray[11] as AllowanceAmountScenario,
- zrxFeeBalance: fillScenarioArray[12] as BalanceAmountScenario,
- zrxFeeAllowance: fillScenarioArray[13] as AllowanceAmountScenario,
- },
- takerStateScenario: {
- traderAssetBalance: fillScenarioArray[14] as BalanceAmountScenario,
- traderAssetAllowance: fillScenarioArray[15] as AllowanceAmountScenario,
- zrxFeeBalance: fillScenarioArray[16] as BalanceAmountScenario,
- zrxFeeAllowance: fillScenarioArray[17] as AllowanceAmountScenario,
- },
- };
- // tslint:enable:custom-no-magic-numbers
- return fillScenario;
- });
-
- return fillScenarios;
- }
- /**
- * Recursive implementation of generating all combinations of the supplied
- * string-containing arrays.
- */
- private static _getAllCombinations(arrays: string[][]): string[][] {
- // Base case
- if (arrays.length === 1) {
- const remainingValues = _.map(arrays[0], val => {
- return [val];
- });
- return remainingValues;
- } else {
- const result = [];
- const restOfArrays = arrays.slice(1);
- const allCombinationsOfRemaining = FillOrderCombinatorialUtils._getAllCombinations(restOfArrays); // recur with the rest of array
- // tslint:disable:prefer-for-of
- for (let i = 0; i < allCombinationsOfRemaining.length; i++) {
- for (let j = 0; j < arrays[0].length; j++) {
- result.push([arrays[0][j], ...allCombinationsOfRemaining[i]]);
- }
- }
- // tslint:enable:prefer-for-of
- return result;
- }
- }
- constructor(
- orderFactory: OrderFactoryFromScenario,
- ownerAddress: string,
- makerAddress: string,
- makerPrivateKey: Buffer,
- takerAddress: string,
- zrxAssetData: string,
- exchangeWrapper: ExchangeWrapper,
- assetWrapper: AssetWrapper,
- testLibsContract: TestLibsContract,
- ) {
- this.orderFactory = orderFactory;
- this.ownerAddress = ownerAddress;
- this.makerAddress = makerAddress;
- this.makerPrivateKey = makerPrivateKey;
- this.takerAddress = takerAddress;
- this.zrxAssetData = zrxAssetData;
- this.exchangeWrapper = exchangeWrapper;
- this.assetWrapper = assetWrapper;
- this.testLibsContract = testLibsContract;
- }
- public async testFillOrderScenarioAsync(
- provider: Provider,
- fillScenario: FillScenario,
- isVerbose: boolean = false,
- ): Promise<void> {
- // 1. Generate order
- const order = this.orderFactory.generateOrder(fillScenario.orderScenario);
-
- // 2. Sign order
- const orderHashBuff = orderHashUtils.getOrderHashBuffer(order);
- const signature = signingUtils.signMessage(orderHashBuff, this.makerPrivateKey, SignatureType.EthSign);
- const signedOrder = {
- ...order,
- signature: `0x${signature.toString('hex')}`,
- };
-
- const balanceAndProxyAllowanceFetcher = new SimpleAssetBalanceAndProxyAllowanceFetcher(this.assetWrapper);
- const orderFilledCancelledFetcher = new SimpleOrderFilledCancelledFetcher(
- this.exchangeWrapper,
- this.zrxAssetData,
- );
-
- // 3. Figure out fill amount
- const takerAssetFillAmount = await this._getTakerAssetFillAmountAsync(
- signedOrder,
- fillScenario.takerAssetFillAmountScenario,
- balanceAndProxyAllowanceFetcher,
- orderFilledCancelledFetcher,
- );
-
- // 4. Permutate the maker and taker balance/allowance scenarios
- await this._modifyTraderStateAsync(
- fillScenario.makerStateScenario,
- fillScenario.takerStateScenario,
- signedOrder,
- takerAssetFillAmount,
- );
-
- // 5. If I fill it by X, what are the resulting balances/allowances/filled amounts expected?
- const orderValidationUtils = new OrderValidationUtils(orderFilledCancelledFetcher, provider);
- const lazyStore = new BalanceAndProxyAllowanceLazyStore(balanceAndProxyAllowanceFetcher);
- const exchangeTransferSimulator = new ExchangeTransferSimulator(lazyStore);
-
- let fillRevertReasonIfExists;
- try {
- await orderValidationUtils.validateFillOrderThrowIfInvalidAsync(
- exchangeTransferSimulator,
- provider,
- signedOrder,
- takerAssetFillAmount,
- this.takerAddress,
- this.zrxAssetData,
- );
- if (isVerbose) {
- logUtils.log(`Expecting fillOrder to succeed.`);
- }
- } catch (err) {
- fillRevertReasonIfExists = err.message;
- if (isVerbose) {
- logUtils.log(`Expecting fillOrder to fail with:`);
- logUtils.log(err);
- }
- }
-
- // 6. Fill the order
- await this._fillOrderAndAssertOutcomeAsync(
- signedOrder,
- takerAssetFillAmount,
- lazyStore,
- fillRevertReasonIfExists,
- );
-
- await this._abiEncodeFillOrderAndAssertOutcomeAsync(signedOrder, takerAssetFillAmount);
- }
- private async _fillOrderAndAssertOutcomeAsync(
- signedOrder: SignedOrder,
- takerAssetFillAmount: BigNumber,
- lazyStore: BalanceAndProxyAllowanceLazyStore,
- fillRevertReasonIfExists: RevertReason | undefined,
- ): Promise<void> {
- if (!_.isUndefined(fillRevertReasonIfExists)) {
- return expectTransactionFailedAsync(
- this.exchangeWrapper.fillOrderAsync(signedOrder, this.takerAddress, { takerAssetFillAmount }),
- fillRevertReasonIfExists,
- );
- }
-
- const makerAddress = signedOrder.makerAddress;
- const makerAssetData = signedOrder.makerAssetData;
- const takerAssetData = signedOrder.takerAssetData;
- const feeRecipient = signedOrder.feeRecipientAddress;
-
- const expMakerAssetBalanceOfMaker = await lazyStore.getBalanceAsync(makerAssetData, makerAddress);
- const expMakerAssetAllowanceOfMaker = await lazyStore.getProxyAllowanceAsync(makerAssetData, makerAddress);
- const expTakerAssetBalanceOfMaker = await lazyStore.getBalanceAsync(takerAssetData, makerAddress);
- const expZRXAssetBalanceOfMaker = await lazyStore.getBalanceAsync(this.zrxAssetData, makerAddress);
- const expZRXAssetAllowanceOfMaker = await lazyStore.getProxyAllowanceAsync(this.zrxAssetData, makerAddress);
- const expTakerAssetBalanceOfTaker = await lazyStore.getBalanceAsync(takerAssetData, this.takerAddress);
- const expTakerAssetAllowanceOfTaker = await lazyStore.getProxyAllowanceAsync(takerAssetData, this.takerAddress);
- const expMakerAssetBalanceOfTaker = await lazyStore.getBalanceAsync(makerAssetData, this.takerAddress);
- const expZRXAssetBalanceOfTaker = await lazyStore.getBalanceAsync(this.zrxAssetData, this.takerAddress);
- const expZRXAssetAllowanceOfTaker = await lazyStore.getProxyAllowanceAsync(
- this.zrxAssetData,
- this.takerAddress,
- );
- const expZRXAssetBalanceOfFeeRecipient = await lazyStore.getBalanceAsync(this.zrxAssetData, feeRecipient);
-
- const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
- const alreadyFilledTakerAmount = await this.exchangeWrapper.getTakerAssetFilledAmountAsync(orderHash);
- const remainingTakerAmountToFill = signedOrder.takerAssetAmount.minus(alreadyFilledTakerAmount);
- const expFilledTakerAmount = takerAssetFillAmount.gt(remainingTakerAmountToFill)
- ? remainingTakerAmountToFill
- : alreadyFilledTakerAmount.add(takerAssetFillAmount);
-
- const expFilledMakerAmount = orderUtils.getPartialAmountFloor(
- expFilledTakerAmount,
- signedOrder.takerAssetAmount,
- signedOrder.makerAssetAmount,
- );
- const expMakerFeePaid = orderUtils.getPartialAmountFloor(
- expFilledTakerAmount,
- signedOrder.takerAssetAmount,
- signedOrder.makerFee,
- );
- const expTakerFeePaid = orderUtils.getPartialAmountFloor(
- expFilledTakerAmount,
- signedOrder.takerAssetAmount,
- signedOrder.takerFee,
- );
- const fillResults = await this.exchangeWrapper.getFillOrderResultsAsync(signedOrder, this.takerAddress, {
- takerAssetFillAmount,
- });
- expect(fillResults.takerAssetFilledAmount).to.be.bignumber.equal(
- expFilledTakerAmount,
- 'takerAssetFilledAmount',
- );
- expect(fillResults.makerAssetFilledAmount).to.be.bignumber.equal(
- expFilledMakerAmount,
- 'makerAssetFilledAmount',
- );
- expect(fillResults.takerFeePaid).to.be.bignumber.equal(expTakerFeePaid, 'takerFeePaid');
- expect(fillResults.makerFeePaid).to.be.bignumber.equal(expMakerFeePaid, 'makerFeePaid');
-
- // - Let's fill the order!
- const txReceipt = await this.exchangeWrapper.fillOrderAsync(signedOrder, this.takerAddress, {
- takerAssetFillAmount,
- });
-
- const actFilledTakerAmount = await this.exchangeWrapper.getTakerAssetFilledAmountAsync(orderHash);
- expect(actFilledTakerAmount).to.be.bignumber.equal(expFilledTakerAmount, 'filledTakerAmount');
-
- const exchangeLogs = _.filter(
- txReceipt.logs,
- txLog => txLog.address === this.exchangeWrapper.getExchangeAddress(),
- );
- expect(exchangeLogs.length).to.be.equal(1, 'logs length');
- // tslint:disable-next-line:no-unnecessary-type-assertion
- const log = txReceipt.logs[0] as LogWithDecodedArgs<ExchangeFillEventArgs>;
- expect(log.args.makerAddress).to.be.equal(makerAddress, 'log.args.makerAddress');
- expect(log.args.takerAddress).to.be.equal(this.takerAddress, 'log.args.this.takerAddress');
- expect(log.args.feeRecipientAddress).to.be.equal(feeRecipient, 'log.args.feeRecipientAddress');
- expect(log.args.makerAssetFilledAmount).to.be.bignumber.equal(
- expFilledMakerAmount,
- 'log.args.makerAssetFilledAmount',
- );
- expect(log.args.takerAssetFilledAmount).to.be.bignumber.equal(
- expFilledTakerAmount,
- 'log.args.takerAssetFilledAmount',
- );
- expect(log.args.makerFeePaid).to.be.bignumber.equal(expMakerFeePaid, 'log.args.makerFeePaid');
- expect(log.args.takerFeePaid).to.be.bignumber.equal(expTakerFeePaid, 'logs.args.takerFeePaid');
- expect(log.args.orderHash).to.be.equal(orderHash, 'log.args.orderHash');
- expect(log.args.makerAssetData).to.be.equal(makerAssetData, 'log.args.makerAssetData');
- expect(log.args.takerAssetData).to.be.equal(takerAssetData, 'log.args.takerAssetData');
-
- const actMakerAssetBalanceOfMaker = await this.assetWrapper.getBalanceAsync(makerAddress, makerAssetData);
- expect(actMakerAssetBalanceOfMaker).to.be.bignumber.equal(
- expMakerAssetBalanceOfMaker,
- 'makerAssetBalanceOfMaker',
- );
-
- const actMakerAssetAllowanceOfMaker = await this.assetWrapper.getProxyAllowanceAsync(
- makerAddress,
- makerAssetData,
- );
- expect(actMakerAssetAllowanceOfMaker).to.be.bignumber.equal(
- expMakerAssetAllowanceOfMaker,
- 'makerAssetAllowanceOfMaker',
- );
-
- const actTakerAssetBalanceOfMaker = await this.assetWrapper.getBalanceAsync(makerAddress, takerAssetData);
- expect(actTakerAssetBalanceOfMaker).to.be.bignumber.equal(
- expTakerAssetBalanceOfMaker,
- 'takerAssetBalanceOfMaker',
- );
-
- const actZRXAssetBalanceOfMaker = await this.assetWrapper.getBalanceAsync(makerAddress, this.zrxAssetData);
- expect(actZRXAssetBalanceOfMaker).to.be.bignumber.equal(expZRXAssetBalanceOfMaker, 'ZRXAssetBalanceOfMaker');
-
- const actZRXAssetAllowanceOfMaker = await this.assetWrapper.getProxyAllowanceAsync(
- makerAddress,
- this.zrxAssetData,
- );
- expect(actZRXAssetAllowanceOfMaker).to.be.bignumber.equal(
- expZRXAssetAllowanceOfMaker,
- 'ZRXAssetAllowanceOfMaker',
- );
-
- const actTakerAssetBalanceOfTaker = await this.assetWrapper.getBalanceAsync(this.takerAddress, takerAssetData);
- expect(actTakerAssetBalanceOfTaker).to.be.bignumber.equal(
- expTakerAssetBalanceOfTaker,
- 'TakerAssetBalanceOfTaker',
- );
-
- const actTakerAssetAllowanceOfTaker = await this.assetWrapper.getProxyAllowanceAsync(
- this.takerAddress,
- takerAssetData,
- );
-
- expect(actTakerAssetAllowanceOfTaker).to.be.bignumber.equal(
- expTakerAssetAllowanceOfTaker,
- 'TakerAssetAllowanceOfTaker',
- );
-
- const actMakerAssetBalanceOfTaker = await this.assetWrapper.getBalanceAsync(this.takerAddress, makerAssetData);
- expect(actMakerAssetBalanceOfTaker).to.be.bignumber.equal(
- expMakerAssetBalanceOfTaker,
- 'MakerAssetBalanceOfTaker',
- );
-
- const actZRXAssetBalanceOfTaker = await this.assetWrapper.getBalanceAsync(this.takerAddress, this.zrxAssetData);
- expect(actZRXAssetBalanceOfTaker).to.be.bignumber.equal(expZRXAssetBalanceOfTaker, 'ZRXAssetBalanceOfTaker');
-
- const actZRXAssetAllowanceOfTaker = await this.assetWrapper.getProxyAllowanceAsync(
- this.takerAddress,
- this.zrxAssetData,
- );
- expect(actZRXAssetAllowanceOfTaker).to.be.bignumber.equal(
- expZRXAssetAllowanceOfTaker,
- 'ZRXAssetAllowanceOfTaker',
- );
-
- const actZRXAssetBalanceOfFeeRecipient = await this.assetWrapper.getBalanceAsync(
- feeRecipient,
- this.zrxAssetData,
- );
- expect(actZRXAssetBalanceOfFeeRecipient).to.be.bignumber.equal(
- expZRXAssetBalanceOfFeeRecipient,
- 'ZRXAssetBalanceOfFeeRecipient',
- );
- }
- private async _abiEncodeFillOrderAndAssertOutcomeAsync(
- signedOrder: SignedOrder,
- takerAssetFillAmount: BigNumber,
- ): Promise<void> {
- const params = orderUtils.createFill(signedOrder, takerAssetFillAmount);
- const expectedAbiEncodedData = this.exchangeWrapper.abiEncodeFillOrder(signedOrder, { takerAssetFillAmount });
- const libsAbiEncodedData = await this.testLibsContract.publicAbiEncodeFillOrder.callAsync(
- params.order,
- params.takerAssetFillAmount,
- params.signature,
- );
- expect(libsAbiEncodedData).to.be.equal(expectedAbiEncodedData, 'ABIEncodedFillOrderData');
- }
- private async _getTakerAssetFillAmountAsync(
- signedOrder: SignedOrder,
- takerAssetFillAmountScenario: TakerAssetFillAmountScenario,
- balanceAndProxyAllowanceFetcher: SimpleAssetBalanceAndProxyAllowanceFetcher,
- orderFilledCancelledFetcher: SimpleOrderFilledCancelledFetcher,
- ): Promise<BigNumber> {
- const orderStateUtils = new OrderStateUtils(balanceAndProxyAllowanceFetcher, orderFilledCancelledFetcher);
- const fillableTakerAssetAmount = await orderStateUtils.getMaxFillableTakerAssetAmountAsync(
- signedOrder,
- this.takerAddress,
- );
-
- let takerAssetFillAmount;
- switch (takerAssetFillAmountScenario) {
- case TakerAssetFillAmountScenario.Zero:
- takerAssetFillAmount = new BigNumber(0);
- break;
-
- case TakerAssetFillAmountScenario.ExactlyRemainingFillableTakerAssetAmount:
- takerAssetFillAmount = fillableTakerAssetAmount;
- break;
-
- case TakerAssetFillAmountScenario.GreaterThanRemainingFillableTakerAssetAmount:
- takerAssetFillAmount = fillableTakerAssetAmount.add(1);
- break;
-
- case TakerAssetFillAmountScenario.LessThanRemainingFillableTakerAssetAmount:
- const takerAssetProxyId = assetDataUtils.decodeAssetProxyId(signedOrder.takerAssetData);
- const makerAssetProxyId = assetDataUtils.decodeAssetProxyId(signedOrder.makerAssetData);
- const isEitherAssetERC721 =
- takerAssetProxyId === AssetProxyId.ERC721 || makerAssetProxyId === AssetProxyId.ERC721;
- if (isEitherAssetERC721) {
- throw new Error(
- 'Cannot test `TakerAssetFillAmountScenario.LessThanRemainingFillableTakerAssetAmount` together with ERC721 assets since orders involving ERC721 must always be filled exactly.',
- );
- }
- takerAssetFillAmount = fillableTakerAssetAmount.div(2).floor();
- break;
-
- default:
- throw errorUtils.spawnSwitchErr('TakerAssetFillAmountScenario', takerAssetFillAmountScenario);
- }
-
- return takerAssetFillAmount;
- }
- private async _modifyTraderStateAsync(
- makerStateScenario: TraderStateScenario,
- takerStateScenario: TraderStateScenario,
- signedOrder: SignedOrder,
- takerAssetFillAmount: BigNumber,
- ): Promise<void> {
- const makerAssetFillAmount = orderUtils.getPartialAmountFloor(
- takerAssetFillAmount,
- signedOrder.takerAssetAmount,
- signedOrder.makerAssetAmount,
- );
- switch (makerStateScenario.traderAssetBalance) {
- case BalanceAmountScenario.Higher:
- break; // Noop since this is already the default
-
- case BalanceAmountScenario.TooLow:
- if (makerAssetFillAmount.eq(0)) {
- throw new Error(`Cannot set makerAssetBalanceOfMaker TooLow if makerAssetFillAmount is 0`);
- }
- const tooLowBalance = makerAssetFillAmount.minus(1);
- await this.assetWrapper.setBalanceAsync(
- signedOrder.makerAddress,
- signedOrder.makerAssetData,
- tooLowBalance,
- );
- break;
-
- case BalanceAmountScenario.Exact:
- const exactBalance = makerAssetFillAmount;
- await this.assetWrapper.setBalanceAsync(
- signedOrder.makerAddress,
- signedOrder.makerAssetData,
- exactBalance,
- );
- break;
-
- default:
- throw errorUtils.spawnSwitchErr(
- 'makerStateScenario.traderAssetBalance',
- makerStateScenario.traderAssetBalance,
- );
- }
-
- const makerFee = orderUtils.getPartialAmountFloor(
- takerAssetFillAmount,
- signedOrder.takerAssetAmount,
- signedOrder.makerFee,
- );
- switch (makerStateScenario.zrxFeeBalance) {
- case BalanceAmountScenario.Higher:
- break; // Noop since this is already the default
-
- case BalanceAmountScenario.TooLow:
- if (makerFee.eq(0)) {
- throw new Error(`Cannot set zrxAsserBalanceOfMaker TooLow if makerFee is 0`);
- }
- const tooLowBalance = makerFee.minus(1);
- await this.assetWrapper.setBalanceAsync(signedOrder.makerAddress, this.zrxAssetData, tooLowBalance);
- break;
-
- case BalanceAmountScenario.Exact:
- const exactBalance = makerFee;
- await this.assetWrapper.setBalanceAsync(signedOrder.makerAddress, this.zrxAssetData, exactBalance);
- break;
-
- default:
- throw errorUtils.spawnSwitchErr('makerStateScenario.zrxFeeBalance', makerStateScenario.zrxFeeBalance);
- }
-
- switch (makerStateScenario.traderAssetAllowance) {
- case AllowanceAmountScenario.Higher:
- break; // Noop since this is already the default
-
- case AllowanceAmountScenario.TooLow:
- const tooLowAllowance = makerAssetFillAmount.minus(1);
- await this.assetWrapper.setProxyAllowanceAsync(
- signedOrder.makerAddress,
- signedOrder.makerAssetData,
- tooLowAllowance,
- );
- break;
-
- case AllowanceAmountScenario.Exact:
- const exactAllowance = makerAssetFillAmount;
- await this.assetWrapper.setProxyAllowanceAsync(
- signedOrder.makerAddress,
- signedOrder.makerAssetData,
- exactAllowance,
- );
- break;
-
- case AllowanceAmountScenario.Unlimited:
- await this.assetWrapper.setProxyAllowanceAsync(
- signedOrder.makerAddress,
- signedOrder.makerAssetData,
- constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS,
- );
- break;
-
- default:
- throw errorUtils.spawnSwitchErr(
- 'makerStateScenario.traderAssetAllowance',
- makerStateScenario.traderAssetAllowance,
- );
- }
-
- switch (makerStateScenario.zrxFeeAllowance) {
- case AllowanceAmountScenario.Higher:
- break; // Noop since this is already the default
-
- case AllowanceAmountScenario.TooLow:
- const tooLowAllowance = makerFee.minus(1);
- await this.assetWrapper.setProxyAllowanceAsync(
- signedOrder.makerAddress,
- this.zrxAssetData,
- tooLowAllowance,
- );
- break;
-
- case AllowanceAmountScenario.Exact:
- const exactAllowance = makerFee;
- await this.assetWrapper.setProxyAllowanceAsync(
- signedOrder.makerAddress,
- this.zrxAssetData,
- exactAllowance,
- );
- break;
-
- case AllowanceAmountScenario.Unlimited:
- await this.assetWrapper.setProxyAllowanceAsync(
- signedOrder.makerAddress,
- this.zrxAssetData,
- constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS,
- );
- break;
-
- default:
- throw errorUtils.spawnSwitchErr(
- 'makerStateScenario.zrxFeeAllowance',
- makerStateScenario.zrxFeeAllowance,
- );
- }
-
- switch (takerStateScenario.traderAssetBalance) {
- case BalanceAmountScenario.Higher:
- break; // Noop since this is already the default
-
- case BalanceAmountScenario.TooLow:
- if (takerAssetFillAmount.eq(0)) {
- throw new Error(`Cannot set takerAssetBalanceOfTaker TooLow if takerAssetFillAmount is 0`);
- }
- const tooLowBalance = takerAssetFillAmount.minus(1);
- await this.assetWrapper.setBalanceAsync(this.takerAddress, signedOrder.takerAssetData, tooLowBalance);
- break;
-
- case BalanceAmountScenario.Exact:
- const exactBalance = takerAssetFillAmount;
- await this.assetWrapper.setBalanceAsync(this.takerAddress, signedOrder.takerAssetData, exactBalance);
- break;
-
- default:
- throw errorUtils.spawnSwitchErr(
- 'takerStateScenario.traderAssetBalance',
- takerStateScenario.traderAssetBalance,
- );
- }
-
- const takerFee = orderUtils.getPartialAmountFloor(
- takerAssetFillAmount,
- signedOrder.takerAssetAmount,
- signedOrder.takerFee,
- );
- switch (takerStateScenario.zrxFeeBalance) {
- case BalanceAmountScenario.Higher:
- break; // Noop since this is already the default
-
- case BalanceAmountScenario.TooLow:
- if (takerFee.eq(0)) {
- throw new Error(`Cannot set zrxAssetBalanceOfTaker TooLow if takerFee is 0`);
- }
- const tooLowBalance = takerFee.minus(1);
- await this.assetWrapper.setBalanceAsync(this.takerAddress, this.zrxAssetData, tooLowBalance);
- break;
-
- case BalanceAmountScenario.Exact:
- const exactBalance = takerFee;
- await this.assetWrapper.setBalanceAsync(this.takerAddress, this.zrxAssetData, exactBalance);
- break;
-
- default:
- throw errorUtils.spawnSwitchErr('takerStateScenario.zrxFeeBalance', takerStateScenario.zrxFeeBalance);
- }
-
- switch (takerStateScenario.traderAssetAllowance) {
- case AllowanceAmountScenario.Higher:
- break; // Noop since this is already the default
-
- case AllowanceAmountScenario.TooLow:
- const tooLowAllowance = takerAssetFillAmount.minus(1);
- await this.assetWrapper.setProxyAllowanceAsync(
- this.takerAddress,
- signedOrder.takerAssetData,
- tooLowAllowance,
- );
- break;
-
- case AllowanceAmountScenario.Exact:
- const exactAllowance = takerAssetFillAmount;
- await this.assetWrapper.setProxyAllowanceAsync(
- this.takerAddress,
- signedOrder.takerAssetData,
- exactAllowance,
- );
- break;
-
- case AllowanceAmountScenario.Unlimited:
- await this.assetWrapper.setProxyAllowanceAsync(
- this.takerAddress,
- signedOrder.takerAssetData,
- constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS,
- );
- break;
-
- default:
- throw errorUtils.spawnSwitchErr(
- 'takerStateScenario.traderAssetAllowance',
- takerStateScenario.traderAssetAllowance,
- );
- }
-
- switch (takerStateScenario.zrxFeeAllowance) {
- case AllowanceAmountScenario.Higher:
- break; // Noop since this is already the default
-
- case AllowanceAmountScenario.TooLow:
- const tooLowAllowance = takerFee.minus(1);
- await this.assetWrapper.setProxyAllowanceAsync(this.takerAddress, this.zrxAssetData, tooLowAllowance);
- break;
-
- case AllowanceAmountScenario.Exact:
- const exactAllowance = takerFee;
- await this.assetWrapper.setProxyAllowanceAsync(this.takerAddress, this.zrxAssetData, exactAllowance);
- break;
-
- case AllowanceAmountScenario.Unlimited:
- await this.assetWrapper.setProxyAllowanceAsync(
- this.takerAddress,
- this.zrxAssetData,
- constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS,
- );
- break;
-
- default:
- throw errorUtils.spawnSwitchErr(
- 'takerStateScenario.zrxFeeAllowance',
- takerStateScenario.zrxFeeAllowance,
- );
- }
- }
-} // tslint:disable:max-file-line-count
diff --git a/packages/contracts/test/utils/formatters.ts b/packages/contracts/test/utils/formatters.ts
deleted file mode 100644
index 813eb45db..000000000
--- a/packages/contracts/test/utils/formatters.ts
+++ /dev/null
@@ -1,68 +0,0 @@
-import { SignedOrder } from '@0x/types';
-import { BigNumber } from '@0x/utils';
-import * as _ from 'lodash';
-
-import { constants } from './constants';
-import { orderUtils } from './order_utils';
-import { BatchCancelOrders, BatchFillOrders, MarketBuyOrders, MarketSellOrders } from './types';
-
-export const formatters = {
- createBatchFill(signedOrders: SignedOrder[], takerAssetFillAmounts: BigNumber[] = []): BatchFillOrders {
- const batchFill: BatchFillOrders = {
- orders: [],
- signatures: [],
- takerAssetFillAmounts,
- };
- _.forEach(signedOrders, signedOrder => {
- const orderWithoutExchangeAddress = orderUtils.getOrderWithoutExchangeAddress(signedOrder);
- batchFill.orders.push(orderWithoutExchangeAddress);
- batchFill.signatures.push(signedOrder.signature);
- if (takerAssetFillAmounts.length < signedOrders.length) {
- batchFill.takerAssetFillAmounts.push(signedOrder.takerAssetAmount);
- }
- });
- return batchFill;
- },
- createMarketSellOrders(signedOrders: SignedOrder[], takerAssetFillAmount: BigNumber): MarketSellOrders {
- const marketSellOrders: MarketSellOrders = {
- orders: [],
- signatures: [],
- takerAssetFillAmount,
- };
- _.forEach(signedOrders, (signedOrder, i) => {
- const orderWithoutExchangeAddress = orderUtils.getOrderWithoutExchangeAddress(signedOrder);
- if (i !== 0) {
- orderWithoutExchangeAddress.takerAssetData = constants.NULL_BYTES;
- }
- marketSellOrders.orders.push(orderWithoutExchangeAddress);
- marketSellOrders.signatures.push(signedOrder.signature);
- });
- return marketSellOrders;
- },
- createMarketBuyOrders(signedOrders: SignedOrder[], makerAssetFillAmount: BigNumber): MarketBuyOrders {
- const marketBuyOrders: MarketBuyOrders = {
- orders: [],
- signatures: [],
- makerAssetFillAmount,
- };
- _.forEach(signedOrders, (signedOrder, i) => {
- const orderWithoutExchangeAddress = orderUtils.getOrderWithoutExchangeAddress(signedOrder);
- if (i !== 0) {
- orderWithoutExchangeAddress.makerAssetData = constants.NULL_BYTES;
- }
- marketBuyOrders.orders.push(orderWithoutExchangeAddress);
- marketBuyOrders.signatures.push(signedOrder.signature);
- });
- return marketBuyOrders;
- },
- createBatchCancel(signedOrders: SignedOrder[]): BatchCancelOrders {
- const batchCancel: BatchCancelOrders = {
- orders: [],
- };
- _.forEach(signedOrders, signedOrder => {
- const orderWithoutExchangeAddress = orderUtils.getOrderWithoutExchangeAddress(signedOrder);
- batchCancel.orders.push(orderWithoutExchangeAddress);
- });
- return batchCancel;
- },
-};
diff --git a/packages/contracts/test/utils/forwarder_wrapper.ts b/packages/contracts/test/utils/forwarder_wrapper.ts
deleted file mode 100644
index a0bfcfe1d..000000000
--- a/packages/contracts/test/utils/forwarder_wrapper.ts
+++ /dev/null
@@ -1,121 +0,0 @@
-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 { constants } from './constants';
-import { formatters } from './formatters';
-import { LogDecoder } from './log_decoder';
-import { MarketSellOrders } from './types';
-
-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)
- .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);
- }
- 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/packages/contracts/test/utils/log_decoder.ts b/packages/contracts/test/utils/log_decoder.ts
deleted file mode 100644
index 05b0a9204..000000000
--- a/packages/contracts/test/utils/log_decoder.ts
+++ /dev/null
@@ -1,53 +0,0 @@
-import { AbiDecoder, BigNumber } from '@0x/utils';
-import { Web3Wrapper } from '@0x/web3-wrapper';
-import {
- AbiDefinition,
- ContractArtifact,
- DecodedLogArgs,
- LogEntry,
- LogWithDecodedArgs,
- RawLog,
- TransactionReceiptWithDecodedLogs,
-} from 'ethereum-types';
-import * as _ from 'lodash';
-
-import { artifacts } from '../../src/artifacts';
-
-import { constants } from './constants';
-
-export class LogDecoder {
- private readonly _web3Wrapper: Web3Wrapper;
- private readonly _abiDecoder: AbiDecoder;
- public static wrapLogBigNumbers(log: any): any {
- const argNames = _.keys(log.args);
- for (const argName of argNames) {
- const isWeb3BigNumber = _.startsWith(log.args[argName].constructor.toString(), 'function BigNumber(');
- if (isWeb3BigNumber) {
- log.args[argName] = new BigNumber(log.args[argName]);
- }
- }
- }
- constructor(web3Wrapper: Web3Wrapper) {
- this._web3Wrapper = web3Wrapper;
- const abiArrays: AbiDefinition[][] = [];
- _.forEach(artifacts, (artifact: ContractArtifact) => {
- const compilerOutput = artifact.compilerOutput;
- abiArrays.push(compilerOutput.abi);
- });
- this._abiDecoder = new AbiDecoder(abiArrays);
- }
- public decodeLogOrThrow<ArgsType extends DecodedLogArgs>(log: LogEntry): LogWithDecodedArgs<ArgsType> | RawLog {
- const logWithDecodedArgsOrLog = this._abiDecoder.tryToDecodeLogOrNoop(log);
- // tslint:disable-next-line:no-unnecessary-type-assertion
- if (_.isUndefined((logWithDecodedArgsOrLog as LogWithDecodedArgs<ArgsType>).args)) {
- throw new Error(`Unable to decode log: ${JSON.stringify(log)}`);
- }
- LogDecoder.wrapLogBigNumbers(logWithDecodedArgsOrLog);
- return logWithDecodedArgsOrLog;
- }
- public async getTxWithDecodedLogsAsync(txHash: string): Promise<TransactionReceiptWithDecodedLogs> {
- const tx = await this._web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS);
- tx.logs = _.map(tx.logs, log => this.decodeLogOrThrow(log));
- return tx;
- }
-}
diff --git a/packages/contracts/test/utils/match_order_tester.ts b/packages/contracts/test/utils/match_order_tester.ts
deleted file mode 100644
index 6c2c84959..000000000
--- a/packages/contracts/test/utils/match_order_tester.ts
+++ /dev/null
@@ -1,566 +0,0 @@
-import { assetDataUtils, orderHashUtils } from '@0x/order-utils';
-import { AssetProxyId, SignedOrder } from '@0x/types';
-import { BigNumber } from '@0x/utils';
-import * as chai from 'chai';
-import * as _ from 'lodash';
-
-import { TransactionReceiptWithDecodedLogs } from '../../../../node_modules/ethereum-types';
-
-import { chaiSetup } from './chai_setup';
-import { ERC20Wrapper } from './erc20_wrapper';
-import { ERC721Wrapper } from './erc721_wrapper';
-import { ExchangeWrapper } from './exchange_wrapper';
-import {
- ERC20BalancesByOwner,
- ERC721TokenIdsByOwner,
- OrderInfo,
- OrderStatus,
- TransferAmountsByMatchOrders as TransferAmounts,
- TransferAmountsLoggedByMatchOrders as LoggedTransferAmounts,
-} from './types';
-
-chaiSetup.configure();
-const expect = chai.expect;
-
-export class MatchOrderTester {
- private readonly _exchangeWrapper: ExchangeWrapper;
- private readonly _erc20Wrapper: ERC20Wrapper;
- private readonly _erc721Wrapper: ERC721Wrapper;
- private readonly _feeTokenAddress: string;
- /// @dev Checks values from the logs produced by Exchange.matchOrders against the expected transfer amounts.
- /// Values include the amounts transferred from the left/right makers and taker, along with
- /// the fees paid on each matched order. These are also the return values of MatchOrders.
- /// @param signedOrderLeft First matched order.
- /// @param signedOrderRight Second matched order.
- /// @param transactionReceipt Transaction receipt and logs produced by Exchange.matchOrders.
- /// @param takerAddress Address of taker (account that called Exchange.matchOrders)
- /// @param expectedTransferAmounts Expected amounts transferred as a result of order matching.
- private static async _assertLogsAsync(
- signedOrderLeft: SignedOrder,
- signedOrderRight: SignedOrder,
- transactionReceipt: TransactionReceiptWithDecodedLogs,
- takerAddress: string,
- expectedTransferAmounts: TransferAmounts,
- ): Promise<void> {
- // Should have two fill event logs -- one for each order.
- const transactionFillLogs = _.filter(transactionReceipt.logs, ['event', 'Fill']);
- expect(transactionFillLogs.length, 'Checking number of logs').to.be.equal(2);
- // First log is for left fill
- const leftLog = (transactionFillLogs[0] as any).args as LoggedTransferAmounts;
- expect(leftLog.makerAddress, 'Checking logged maker address of left order').to.be.equal(
- signedOrderLeft.makerAddress,
- );
- expect(leftLog.takerAddress, 'Checking logged taker address of right order').to.be.equal(takerAddress);
- const amountBoughtByLeftMaker = new BigNumber(leftLog.takerAssetFilledAmount);
- const amountSoldByLeftMaker = new BigNumber(leftLog.makerAssetFilledAmount);
- const feePaidByLeftMaker = new BigNumber(leftLog.makerFeePaid);
- const feePaidByTakerLeft = new BigNumber(leftLog.takerFeePaid);
- // Second log is for right fill
- const rightLog = (transactionFillLogs[1] as any).args as LoggedTransferAmounts;
- expect(rightLog.makerAddress, 'Checking logged maker address of right order').to.be.equal(
- signedOrderRight.makerAddress,
- );
- expect(rightLog.takerAddress, 'Checking loggerd taker address of right order').to.be.equal(takerAddress);
- const amountBoughtByRightMaker = new BigNumber(rightLog.takerAssetFilledAmount);
- const amountSoldByRightMaker = new BigNumber(rightLog.makerAssetFilledAmount);
- const feePaidByRightMaker = new BigNumber(rightLog.makerFeePaid);
- const feePaidByTakerRight = new BigNumber(rightLog.takerFeePaid);
- // Derive amount received by taker
- const amountReceivedByTaker = amountSoldByLeftMaker.sub(amountBoughtByRightMaker);
- // Assert log values - left order
- expect(amountBoughtByLeftMaker, 'Checking logged amount bought by left maker').to.be.bignumber.equal(
- expectedTransferAmounts.amountBoughtByLeftMaker,
- );
- expect(amountSoldByLeftMaker, 'Checking logged amount sold by left maker').to.be.bignumber.equal(
- expectedTransferAmounts.amountSoldByLeftMaker,
- );
- expect(feePaidByLeftMaker, 'Checking logged fee paid by left maker').to.be.bignumber.equal(
- expectedTransferAmounts.feePaidByLeftMaker,
- );
- expect(feePaidByTakerLeft, 'Checking logged fee paid on left order by taker').to.be.bignumber.equal(
- expectedTransferAmounts.feePaidByTakerLeft,
- );
- // Assert log values - right order
- expect(amountBoughtByRightMaker, 'Checking logged amount bought by right maker').to.be.bignumber.equal(
- expectedTransferAmounts.amountBoughtByRightMaker,
- );
- expect(amountSoldByRightMaker, 'Checking logged amount sold by right maker').to.be.bignumber.equal(
- expectedTransferAmounts.amountSoldByRightMaker,
- );
- expect(feePaidByRightMaker, 'Checking logged fee paid by right maker').to.be.bignumber.equal(
- expectedTransferAmounts.feePaidByRightMaker,
- );
- expect(feePaidByTakerRight, 'Checking logged fee paid on right order by taker').to.be.bignumber.equal(
- expectedTransferAmounts.feePaidByTakerRight,
- );
- // Assert derived amount received by taker
- expect(amountReceivedByTaker, 'Checking logged amount received by taker').to.be.bignumber.equal(
- expectedTransferAmounts.amountReceivedByTaker,
- );
- }
- /// @dev Asserts all expected ERC20 and ERC721 account holdings match the real holdings.
- /// @param expectedERC20BalancesByOwner Expected ERC20 balances.
- /// @param realERC20BalancesByOwner Real ERC20 balances.
- /// @param expectedERC721TokenIdsByOwner Expected ERC721 token owners.
- /// @param realERC721TokenIdsByOwner Real ERC20 token owners.
- private static async _assertAllKnownBalancesAsync(
- expectedERC20BalancesByOwner: ERC20BalancesByOwner,
- realERC20BalancesByOwner: ERC20BalancesByOwner,
- expectedERC721TokenIdsByOwner: ERC721TokenIdsByOwner,
- realERC721TokenIdsByOwner: ERC721TokenIdsByOwner,
- ): Promise<void> {
- // ERC20 Balances
- const areERC20BalancesEqual = _.isEqual(expectedERC20BalancesByOwner, realERC20BalancesByOwner);
- expect(areERC20BalancesEqual, 'Checking all known ERC20 account balances').to.be.true();
- // ERC721 Token Ids
- const sortedExpectedNewERC721TokenIdsByOwner = _.mapValues(expectedERC721TokenIdsByOwner, tokenIdsByOwner => {
- _.mapValues(tokenIdsByOwner, tokenIds => {
- _.sortBy(tokenIds);
- });
- });
- const sortedNewERC721TokenIdsByOwner = _.mapValues(realERC721TokenIdsByOwner, tokenIdsByOwner => {
- _.mapValues(tokenIdsByOwner, tokenIds => {
- _.sortBy(tokenIds);
- });
- });
- const areERC721TokenIdsEqual = _.isEqual(
- sortedExpectedNewERC721TokenIdsByOwner,
- sortedNewERC721TokenIdsByOwner,
- );
- expect(areERC721TokenIdsEqual, 'Checking all known ERC721 account balances').to.be.true();
- }
- /// @dev Constructs new MatchOrderTester.
- /// @param exchangeWrapper Used to call to the Exchange.
- /// @param erc20Wrapper Used to fetch ERC20 balances.
- /// @param erc721Wrapper Used to fetch ERC721 token owners.
- /// @param feeTokenAddress Address of ERC20 fee token.
- constructor(
- exchangeWrapper: ExchangeWrapper,
- erc20Wrapper: ERC20Wrapper,
- erc721Wrapper: ERC721Wrapper,
- feeTokenAddress: string,
- ) {
- this._exchangeWrapper = exchangeWrapper;
- this._erc20Wrapper = erc20Wrapper;
- this._erc721Wrapper = erc721Wrapper;
- this._feeTokenAddress = feeTokenAddress;
- }
- /// @dev Matches two complementary orders and asserts results.
- /// @param signedOrderLeft First matched order.
- /// @param signedOrderRight Second matched order.
- /// @param takerAddress Address of taker (the address who matched the two orders)
- /// @param erc20BalancesByOwner Current ERC20 balances.
- /// @param erc721TokenIdsByOwner Current ERC721 token owners.
- /// @param expectedTransferAmounts Expected amounts transferred as a result of order matching.
- /// @param initialLeftOrderFilledAmount How much left order has been filled, prior to matching orders.
- /// @param initialRightOrderFilledAmount How much the right order has been filled, prior to matching orders.
- /// @return New ERC20 balances & ERC721 token owners.
- public async matchOrdersAndAssertEffectsAsync(
- signedOrderLeft: SignedOrder,
- signedOrderRight: SignedOrder,
- takerAddress: string,
- erc20BalancesByOwner: ERC20BalancesByOwner,
- erc721TokenIdsByOwner: ERC721TokenIdsByOwner,
- expectedTransferAmounts: TransferAmounts,
- initialLeftOrderFilledAmount: BigNumber = new BigNumber(0),
- initialRightOrderFilledAmount: BigNumber = new BigNumber(0),
- ): Promise<[ERC20BalancesByOwner, ERC721TokenIdsByOwner]> {
- // Assert initial order states
- await this._assertInitialOrderStatesAsync(
- signedOrderLeft,
- signedOrderRight,
- initialLeftOrderFilledAmount,
- initialRightOrderFilledAmount,
- );
- // Match left & right orders
- const transactionReceipt = await this._exchangeWrapper.matchOrdersAsync(
- signedOrderLeft,
- signedOrderRight,
- takerAddress,
- );
- const newERC20BalancesByOwner = await this._erc20Wrapper.getBalancesAsync();
- const newERC721TokenIdsByOwner = await this._erc721Wrapper.getBalancesAsync();
- // Assert logs
- await MatchOrderTester._assertLogsAsync(
- signedOrderLeft,
- signedOrderRight,
- transactionReceipt,
- takerAddress,
- expectedTransferAmounts,
- );
- // Assert exchange state
- await this._assertExchangeStateAsync(
- signedOrderLeft,
- signedOrderRight,
- initialLeftOrderFilledAmount,
- initialRightOrderFilledAmount,
- expectedTransferAmounts,
- );
- // Assert balances of makers, taker, and fee recipients
- await this._assertBalancesAsync(
- signedOrderLeft,
- signedOrderRight,
- erc20BalancesByOwner,
- erc721TokenIdsByOwner,
- newERC20BalancesByOwner,
- newERC721TokenIdsByOwner,
- expectedTransferAmounts,
- takerAddress,
- );
- return [newERC20BalancesByOwner, newERC721TokenIdsByOwner];
- }
- /// @dev Asserts initial exchange state for the left and right orders.
- /// @param signedOrderLeft First matched order.
- /// @param signedOrderRight Second matched order.
- /// @param expectedOrderFilledAmountLeft How much left order has been filled, prior to matching orders.
- /// @param expectedOrderFilledAmountRight How much the right order has been filled, prior to matching orders.
- private async _assertInitialOrderStatesAsync(
- signedOrderLeft: SignedOrder,
- signedOrderRight: SignedOrder,
- expectedOrderFilledAmountLeft: BigNumber,
- expectedOrderFilledAmountRight: BigNumber,
- ): Promise<void> {
- // Assert left order initial state
- const orderTakerAssetFilledAmountLeft = await this._exchangeWrapper.getTakerAssetFilledAmountAsync(
- orderHashUtils.getOrderHashHex(signedOrderLeft),
- );
- expect(orderTakerAssetFilledAmountLeft, 'Checking inital state of left order').to.be.bignumber.equal(
- expectedOrderFilledAmountLeft,
- );
- // Assert right order initial state
- const orderTakerAssetFilledAmountRight = await this._exchangeWrapper.getTakerAssetFilledAmountAsync(
- orderHashUtils.getOrderHashHex(signedOrderRight),
- );
- expect(orderTakerAssetFilledAmountRight, 'Checking inital state of right order').to.be.bignumber.equal(
- expectedOrderFilledAmountRight,
- );
- }
- /// @dev Asserts the exchange state against the expected amounts transferred by from matching orders.
- /// @param signedOrderLeft First matched order.
- /// @param signedOrderRight Second matched order.
- /// @param initialLeftOrderFilledAmount How much left order has been filled, prior to matching orders.
- /// @param initialRightOrderFilledAmount How much the right order has been filled, prior to matching orders.
- /// @return TransferAmounts A struct containing the expected transfer amounts.
- private async _assertExchangeStateAsync(
- signedOrderLeft: SignedOrder,
- signedOrderRight: SignedOrder,
- initialLeftOrderFilledAmount: BigNumber,
- initialRightOrderFilledAmount: BigNumber,
- expectedTransferAmounts: TransferAmounts,
- ): Promise<void> {
- // Assert state for left order: amount bought by left maker
- let amountBoughtByLeftMaker = await this._exchangeWrapper.getTakerAssetFilledAmountAsync(
- orderHashUtils.getOrderHashHex(signedOrderLeft),
- );
- amountBoughtByLeftMaker = amountBoughtByLeftMaker.minus(initialLeftOrderFilledAmount);
- expect(amountBoughtByLeftMaker, 'Checking exchange state for left order').to.be.bignumber.equal(
- expectedTransferAmounts.amountBoughtByLeftMaker,
- );
- // Assert state for right order: amount bought by right maker
- let amountBoughtByRightMaker = await this._exchangeWrapper.getTakerAssetFilledAmountAsync(
- orderHashUtils.getOrderHashHex(signedOrderRight),
- );
- amountBoughtByRightMaker = amountBoughtByRightMaker.minus(initialRightOrderFilledAmount);
- expect(amountBoughtByRightMaker, 'Checking exchange state for right order').to.be.bignumber.equal(
- expectedTransferAmounts.amountBoughtByRightMaker,
- );
- // Assert left order status
- const maxAmountBoughtByLeftMaker = signedOrderLeft.takerAssetAmount.minus(initialLeftOrderFilledAmount);
- const leftOrderInfo: OrderInfo = await this._exchangeWrapper.getOrderInfoAsync(signedOrderLeft);
- const leftExpectedStatus = expectedTransferAmounts.amountBoughtByLeftMaker.equals(maxAmountBoughtByLeftMaker)
- ? OrderStatus.FULLY_FILLED
- : OrderStatus.FILLABLE;
- expect(leftOrderInfo.orderStatus as OrderStatus, 'Checking exchange status for left order').to.be.equal(
- leftExpectedStatus,
- );
- // Assert right order status
- const maxAmountBoughtByRightMaker = signedOrderRight.takerAssetAmount.minus(initialRightOrderFilledAmount);
- const rightOrderInfo: OrderInfo = await this._exchangeWrapper.getOrderInfoAsync(signedOrderRight);
- const rightExpectedStatus = expectedTransferAmounts.amountBoughtByRightMaker.equals(maxAmountBoughtByRightMaker)
- ? OrderStatus.FULLY_FILLED
- : OrderStatus.FILLABLE;
- expect(rightOrderInfo.orderStatus as OrderStatus, 'Checking exchange status for right order').to.be.equal(
- rightExpectedStatus,
- );
- }
- /// @dev Asserts account balances after matching orders.
- /// @param signedOrderLeft First matched order.
- /// @param signedOrderRight Second matched order.
- /// @param initialERC20BalancesByOwner ERC20 balances prior to order matching.
- /// @param initialERC721TokenIdsByOwner ERC721 token owners prior to order matching.
- /// @param finalERC20BalancesByOwner ERC20 balances after order matching.
- /// @param finalERC721TokenIdsByOwner ERC721 token owners after order matching.
- /// @param expectedTransferAmounts Expected amounts transferred as a result of order matching.
- /// @param takerAddress Address of taker (account that called Exchange.matchOrders).
- private async _assertBalancesAsync(
- signedOrderLeft: SignedOrder,
- signedOrderRight: SignedOrder,
- initialERC20BalancesByOwner: ERC20BalancesByOwner,
- initialERC721TokenIdsByOwner: ERC721TokenIdsByOwner,
- finalERC20BalancesByOwner: ERC20BalancesByOwner,
- finalERC721TokenIdsByOwner: ERC721TokenIdsByOwner,
- expectedTransferAmounts: TransferAmounts,
- takerAddress: string,
- ): Promise<void> {
- let expectedERC20BalancesByOwner: ERC20BalancesByOwner;
- let expectedERC721TokenIdsByOwner: ERC721TokenIdsByOwner;
- [expectedERC20BalancesByOwner, expectedERC721TokenIdsByOwner] = this._calculateExpectedBalances(
- signedOrderLeft,
- signedOrderRight,
- takerAddress,
- initialERC20BalancesByOwner,
- initialERC721TokenIdsByOwner,
- expectedTransferAmounts,
- );
- // Assert balances of makers, taker, and fee recipients
- await this._assertMakerTakerAndFeeRecipientBalancesAsync(
- signedOrderLeft,
- signedOrderRight,
- expectedERC20BalancesByOwner,
- finalERC20BalancesByOwner,
- expectedERC721TokenIdsByOwner,
- finalERC721TokenIdsByOwner,
- takerAddress,
- );
- // Assert balances for all known accounts
- await MatchOrderTester._assertAllKnownBalancesAsync(
- expectedERC20BalancesByOwner,
- finalERC20BalancesByOwner,
- expectedERC721TokenIdsByOwner,
- finalERC721TokenIdsByOwner,
- );
- }
- /// @dev Calculates the expected balances of order makers, fee recipients, and the taker,
- /// as a result of matching two orders.
- /// @param signedOrderRight First matched order.
- /// @param signedOrderRight Second matched order.
- /// @param takerAddress Address of taker (the address who matched the two orders)
- /// @param erc20BalancesByOwner Current ERC20 balances.
- /// @param erc721TokenIdsByOwner Current ERC721 token owners.
- /// @param expectedTransferAmounts Expected amounts transferred as a result of order matching.
- /// @return Expected ERC20 balances & ERC721 token owners after orders have been matched.
- private _calculateExpectedBalances(
- signedOrderLeft: SignedOrder,
- signedOrderRight: SignedOrder,
- takerAddress: string,
- erc20BalancesByOwner: ERC20BalancesByOwner,
- erc721TokenIdsByOwner: ERC721TokenIdsByOwner,
- expectedTransferAmounts: TransferAmounts,
- ): [ERC20BalancesByOwner, ERC721TokenIdsByOwner] {
- const makerAddressLeft = signedOrderLeft.makerAddress;
- const makerAddressRight = signedOrderRight.makerAddress;
- const feeRecipientAddressLeft = signedOrderLeft.feeRecipientAddress;
- const feeRecipientAddressRight = signedOrderRight.feeRecipientAddress;
- // Operations are performed on copies of the balances
- const expectedNewERC20BalancesByOwner = _.cloneDeep(erc20BalancesByOwner);
- const expectedNewERC721TokenIdsByOwner = _.cloneDeep(erc721TokenIdsByOwner);
- // Left Maker Asset (Right Taker Asset)
- const makerAssetProxyIdLeft = assetDataUtils.decodeAssetProxyId(signedOrderLeft.makerAssetData);
- if (makerAssetProxyIdLeft === AssetProxyId.ERC20) {
- // Decode asset data
- const erc20AssetData = assetDataUtils.decodeERC20AssetData(signedOrderLeft.makerAssetData);
- const makerAssetAddressLeft = erc20AssetData.tokenAddress;
- const takerAssetAddressRight = makerAssetAddressLeft;
- // Left Maker
- expectedNewERC20BalancesByOwner[makerAddressLeft][makerAssetAddressLeft] = expectedNewERC20BalancesByOwner[
- makerAddressLeft
- ][makerAssetAddressLeft].minus(expectedTransferAmounts.amountSoldByLeftMaker);
- // Right Maker
- expectedNewERC20BalancesByOwner[makerAddressRight][
- takerAssetAddressRight
- ] = expectedNewERC20BalancesByOwner[makerAddressRight][takerAssetAddressRight].add(
- expectedTransferAmounts.amountBoughtByRightMaker,
- );
- // Taker
- expectedNewERC20BalancesByOwner[takerAddress][makerAssetAddressLeft] = expectedNewERC20BalancesByOwner[
- takerAddress
- ][makerAssetAddressLeft].add(expectedTransferAmounts.amountReceivedByTaker);
- } else if (makerAssetProxyIdLeft === AssetProxyId.ERC721) {
- // Decode asset data
- const erc721AssetData = assetDataUtils.decodeERC721AssetData(signedOrderLeft.makerAssetData);
- const makerAssetAddressLeft = erc721AssetData.tokenAddress;
- const makerAssetIdLeft = erc721AssetData.tokenId;
- const takerAssetAddressRight = makerAssetAddressLeft;
- const takerAssetIdRight = makerAssetIdLeft;
- // Left Maker
- _.remove(expectedNewERC721TokenIdsByOwner[makerAddressLeft][makerAssetAddressLeft], makerAssetIdLeft);
- // Right Maker
- expectedNewERC721TokenIdsByOwner[makerAddressRight][takerAssetAddressRight].push(takerAssetIdRight);
- // Taker: Since there is only 1 asset transferred, the taker does not receive any of the left maker asset.
- }
- // Left Taker Asset (Right Maker Asset)
- // Note: This exchange is only between the order makers: the Taker does not receive any of the left taker asset.
- const takerAssetProxyIdLeft = assetDataUtils.decodeAssetProxyId(signedOrderLeft.takerAssetData);
- if (takerAssetProxyIdLeft === AssetProxyId.ERC20) {
- // Decode asset data
- const erc20AssetData = assetDataUtils.decodeERC20AssetData(signedOrderLeft.takerAssetData);
- const takerAssetAddressLeft = erc20AssetData.tokenAddress;
- const makerAssetAddressRight = takerAssetAddressLeft;
- // Left Maker
- expectedNewERC20BalancesByOwner[makerAddressLeft][takerAssetAddressLeft] = expectedNewERC20BalancesByOwner[
- makerAddressLeft
- ][takerAssetAddressLeft].add(expectedTransferAmounts.amountBoughtByLeftMaker);
- // Right Maker
- expectedNewERC20BalancesByOwner[makerAddressRight][
- makerAssetAddressRight
- ] = expectedNewERC20BalancesByOwner[makerAddressRight][makerAssetAddressRight].minus(
- expectedTransferAmounts.amountSoldByRightMaker,
- );
- } else if (takerAssetProxyIdLeft === AssetProxyId.ERC721) {
- // Decode asset data
- const erc721AssetData = assetDataUtils.decodeERC721AssetData(signedOrderRight.makerAssetData);
- const makerAssetAddressRight = erc721AssetData.tokenAddress;
- const makerAssetIdRight = erc721AssetData.tokenId;
- const takerAssetAddressLeft = makerAssetAddressRight;
- const takerAssetIdLeft = makerAssetIdRight;
- // Right Maker
- _.remove(expectedNewERC721TokenIdsByOwner[makerAddressRight][makerAssetAddressRight], makerAssetIdRight);
- // Left Maker
- expectedNewERC721TokenIdsByOwner[makerAddressLeft][takerAssetAddressLeft].push(takerAssetIdLeft);
- }
- // Left Maker Fees
- expectedNewERC20BalancesByOwner[makerAddressLeft][this._feeTokenAddress] = expectedNewERC20BalancesByOwner[
- makerAddressLeft
- ][this._feeTokenAddress].minus(expectedTransferAmounts.feePaidByLeftMaker);
- // Right Maker Fees
- expectedNewERC20BalancesByOwner[makerAddressRight][this._feeTokenAddress] = expectedNewERC20BalancesByOwner[
- makerAddressRight
- ][this._feeTokenAddress].minus(expectedTransferAmounts.feePaidByRightMaker);
- // Taker Fees
- expectedNewERC20BalancesByOwner[takerAddress][this._feeTokenAddress] = expectedNewERC20BalancesByOwner[
- takerAddress
- ][this._feeTokenAddress].minus(
- expectedTransferAmounts.feePaidByTakerLeft.add(expectedTransferAmounts.feePaidByTakerRight),
- );
- // Left Fee Recipient Fees
- expectedNewERC20BalancesByOwner[feeRecipientAddressLeft][
- this._feeTokenAddress
- ] = expectedNewERC20BalancesByOwner[feeRecipientAddressLeft][this._feeTokenAddress].add(
- expectedTransferAmounts.feePaidByLeftMaker.add(expectedTransferAmounts.feePaidByTakerLeft),
- );
- // Right Fee Recipient Fees
- expectedNewERC20BalancesByOwner[feeRecipientAddressRight][
- this._feeTokenAddress
- ] = expectedNewERC20BalancesByOwner[feeRecipientAddressRight][this._feeTokenAddress].add(
- expectedTransferAmounts.feePaidByRightMaker.add(expectedTransferAmounts.feePaidByTakerRight),
- );
-
- return [expectedNewERC20BalancesByOwner, expectedNewERC721TokenIdsByOwner];
- }
- /// @dev Asserts ERC20 account balances and ERC721 token holdings that result from order matching.
- /// Specifically checks balances of makers, taker and fee recipients.
- /// @param signedOrderLeft First matched order.
- /// @param signedOrderRight Second matched order.
- /// @param expectedERC20BalancesByOwner Expected ERC20 balances.
- /// @param realERC20BalancesByOwner Real ERC20 balances.
- /// @param expectedERC721TokenIdsByOwner Expected ERC721 token owners.
- /// @param realERC721TokenIdsByOwner Real ERC20 token owners.
- /// @param takerAddress Address of taker (account that called Exchange.matchOrders).
- private async _assertMakerTakerAndFeeRecipientBalancesAsync(
- signedOrderLeft: SignedOrder,
- signedOrderRight: SignedOrder,
- expectedERC20BalancesByOwner: ERC20BalancesByOwner,
- realERC20BalancesByOwner: ERC20BalancesByOwner,
- expectedERC721TokenIdsByOwner: ERC721TokenIdsByOwner,
- realERC721TokenIdsByOwner: ERC721TokenIdsByOwner,
- takerAddress: string,
- ): Promise<void> {
- // Individual balance comparisons
- const makerAssetProxyIdLeft = assetDataUtils.decodeAssetProxyId(signedOrderLeft.makerAssetData);
- const makerERC20AssetDataLeft =
- makerAssetProxyIdLeft === AssetProxyId.ERC20
- ? assetDataUtils.decodeERC20AssetData(signedOrderLeft.makerAssetData)
- : assetDataUtils.decodeERC721AssetData(signedOrderLeft.makerAssetData);
- const makerAssetAddressLeft = makerERC20AssetDataLeft.tokenAddress;
- const makerAssetProxyIdRight = assetDataUtils.decodeAssetProxyId(signedOrderRight.makerAssetData);
- const makerERC20AssetDataRight =
- makerAssetProxyIdRight === AssetProxyId.ERC20
- ? assetDataUtils.decodeERC20AssetData(signedOrderRight.makerAssetData)
- : assetDataUtils.decodeERC721AssetData(signedOrderRight.makerAssetData);
- const makerAssetAddressRight = makerERC20AssetDataRight.tokenAddress;
- if (makerAssetProxyIdLeft === AssetProxyId.ERC20) {
- expect(
- realERC20BalancesByOwner[signedOrderLeft.makerAddress][makerAssetAddressLeft],
- 'Checking left maker egress ERC20 account balance',
- ).to.be.bignumber.equal(expectedERC20BalancesByOwner[signedOrderLeft.makerAddress][makerAssetAddressLeft]);
- expect(
- realERC20BalancesByOwner[signedOrderRight.makerAddress][makerAssetAddressLeft],
- 'Checking right maker ingress ERC20 account balance',
- ).to.be.bignumber.equal(expectedERC20BalancesByOwner[signedOrderRight.makerAddress][makerAssetAddressLeft]);
- expect(
- realERC20BalancesByOwner[takerAddress][makerAssetAddressLeft],
- 'Checking taker ingress ERC20 account balance',
- ).to.be.bignumber.equal(expectedERC20BalancesByOwner[takerAddress][makerAssetAddressLeft]);
- } else if (makerAssetProxyIdLeft === AssetProxyId.ERC721) {
- expect(
- realERC721TokenIdsByOwner[signedOrderLeft.makerAddress][makerAssetAddressLeft].sort(),
- 'Checking left maker egress ERC721 account holdings',
- ).to.be.deep.equal(
- expectedERC721TokenIdsByOwner[signedOrderLeft.makerAddress][makerAssetAddressLeft].sort(),
- );
- expect(
- realERC721TokenIdsByOwner[signedOrderRight.makerAddress][makerAssetAddressLeft].sort(),
- 'Checking right maker ERC721 account holdings',
- ).to.be.deep.equal(
- expectedERC721TokenIdsByOwner[signedOrderRight.makerAddress][makerAssetAddressLeft].sort(),
- );
- expect(
- realERC721TokenIdsByOwner[takerAddress][makerAssetAddressLeft].sort(),
- 'Checking taker ingress ERC721 account holdings',
- ).to.be.deep.equal(expectedERC721TokenIdsByOwner[takerAddress][makerAssetAddressLeft].sort());
- } else {
- throw new Error(`Unhandled Asset Proxy ID: ${makerAssetProxyIdLeft}`);
- }
- if (makerAssetProxyIdRight === AssetProxyId.ERC20) {
- expect(
- realERC20BalancesByOwner[signedOrderLeft.makerAddress][makerAssetAddressRight],
- 'Checking left maker ingress ERC20 account balance',
- ).to.be.bignumber.equal(expectedERC20BalancesByOwner[signedOrderLeft.makerAddress][makerAssetAddressRight]);
- expect(
- realERC20BalancesByOwner[signedOrderRight.makerAddress][makerAssetAddressRight],
- 'Checking right maker egress ERC20 account balance',
- ).to.be.bignumber.equal(
- expectedERC20BalancesByOwner[signedOrderRight.makerAddress][makerAssetAddressRight],
- );
- } else if (makerAssetProxyIdRight === AssetProxyId.ERC721) {
- expect(
- realERC721TokenIdsByOwner[signedOrderLeft.makerAddress][makerAssetAddressRight].sort(),
- 'Checking left maker ingress ERC721 account holdings',
- ).to.be.deep.equal(
- expectedERC721TokenIdsByOwner[signedOrderLeft.makerAddress][makerAssetAddressRight].sort(),
- );
- expect(
- realERC721TokenIdsByOwner[signedOrderRight.makerAddress][makerAssetAddressRight],
- 'Checking right maker agress ERC721 account holdings',
- ).to.be.deep.equal(expectedERC721TokenIdsByOwner[signedOrderRight.makerAddress][makerAssetAddressRight]);
- } else {
- throw new Error(`Unhandled Asset Proxy ID: ${makerAssetProxyIdRight}`);
- }
- // Paid fees
- expect(
- realERC20BalancesByOwner[signedOrderLeft.makerAddress][this._feeTokenAddress],
- 'Checking left maker egress ERC20 account fees',
- ).to.be.bignumber.equal(expectedERC20BalancesByOwner[signedOrderLeft.makerAddress][this._feeTokenAddress]);
- expect(
- realERC20BalancesByOwner[signedOrderRight.makerAddress][this._feeTokenAddress],
- 'Checking right maker egress ERC20 account fees',
- ).to.be.bignumber.equal(expectedERC20BalancesByOwner[signedOrderRight.makerAddress][this._feeTokenAddress]);
- expect(
- realERC20BalancesByOwner[takerAddress][this._feeTokenAddress],
- 'Checking taker egress ERC20 account fees',
- ).to.be.bignumber.equal(expectedERC20BalancesByOwner[takerAddress][this._feeTokenAddress]);
- // Received fees
- expect(
- realERC20BalancesByOwner[signedOrderLeft.feeRecipientAddress][this._feeTokenAddress],
- 'Checking left fee recipient ingress ERC20 account fees',
- ).to.be.bignumber.equal(
- expectedERC20BalancesByOwner[signedOrderLeft.feeRecipientAddress][this._feeTokenAddress],
- );
- expect(
- realERC20BalancesByOwner[signedOrderRight.feeRecipientAddress][this._feeTokenAddress],
- 'Checking right fee receipient ingress ERC20 account fees',
- ).to.be.bignumber.equal(
- expectedERC20BalancesByOwner[signedOrderRight.feeRecipientAddress][this._feeTokenAddress],
- );
- }
-} // tslint:disable-line:max-file-line-count
diff --git a/packages/contracts/test/utils/multi_sig_wrapper.ts b/packages/contracts/test/utils/multi_sig_wrapper.ts
deleted file mode 100644
index 74fd3b4d6..000000000
--- a/packages/contracts/test/utils/multi_sig_wrapper.ts
+++ /dev/null
@@ -1,67 +0,0 @@
-import { BigNumber } from '@0x/utils';
-import { Web3Wrapper } from '@0x/web3-wrapper';
-import { Provider, TransactionReceiptWithDecodedLogs } from 'ethereum-types';
-import * as _ from 'lodash';
-
-import { AssetProxyOwnerContract } from '../../generated-wrappers/asset_proxy_owner';
-import { MultiSigWalletContract } from '../../generated-wrappers/multi_sig_wallet';
-
-import { LogDecoder } from './log_decoder';
-
-export class MultiSigWrapper {
- private readonly _multiSig: MultiSigWalletContract;
- private readonly _web3Wrapper: Web3Wrapper;
- private readonly _logDecoder: LogDecoder;
- constructor(multiSigContract: MultiSigWalletContract, provider: Provider) {
- this._multiSig = multiSigContract;
- this._web3Wrapper = new Web3Wrapper(provider);
- this._logDecoder = new LogDecoder(this._web3Wrapper);
- }
- public async submitTransactionAsync(
- destination: string,
- data: string,
- from: string,
- opts: { value?: BigNumber } = {},
- ): Promise<TransactionReceiptWithDecodedLogs> {
- const value = _.isUndefined(opts.value) ? new BigNumber(0) : opts.value;
- const txHash = await this._multiSig.submitTransaction.sendTransactionAsync(destination, value, data, {
- from,
- });
- const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
- return tx;
- }
- public async confirmTransactionAsync(txId: BigNumber, from: string): Promise<TransactionReceiptWithDecodedLogs> {
- const txHash = await this._multiSig.confirmTransaction.sendTransactionAsync(txId, { from });
- const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
- return tx;
- }
- public async revokeConfirmationAsync(txId: BigNumber, from: string): Promise<TransactionReceiptWithDecodedLogs> {
- const txHash = await this._multiSig.revokeConfirmation.sendTransactionAsync(txId, { from });
- const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
- return tx;
- }
- public async executeTransactionAsync(
- txId: BigNumber,
- from: string,
- opts: { gas?: number } = {},
- ): Promise<TransactionReceiptWithDecodedLogs> {
- const txHash = await this._multiSig.executeTransaction.sendTransactionAsync(txId, {
- from,
- gas: opts.gas,
- });
- const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
- return tx;
- }
- public async executeRemoveAuthorizedAddressAtIndexAsync(
- txId: BigNumber,
- from: string,
- ): Promise<TransactionReceiptWithDecodedLogs> {
- // tslint:disable-next-line:no-unnecessary-type-assertion
- const txHash = await (this
- ._multiSig as AssetProxyOwnerContract).executeRemoveAuthorizedAddressAtIndex.sendTransactionAsync(txId, {
- from,
- });
- const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
- return tx;
- }
-}
diff --git a/packages/contracts/test/utils/order_factory.ts b/packages/contracts/test/utils/order_factory.ts
deleted file mode 100644
index 2449d1a8a..000000000
--- a/packages/contracts/test/utils/order_factory.ts
+++ /dev/null
@@ -1,38 +0,0 @@
-import { generatePseudoRandomSalt, orderHashUtils } from '@0x/order-utils';
-import { Order, SignatureType, SignedOrder } from '@0x/types';
-import { BigNumber } from '@0x/utils';
-
-import { getLatestBlockTimestampAsync } from './block_timestamp';
-import { constants } from './constants';
-import { signingUtils } from './signing_utils';
-
-export class OrderFactory {
- private readonly _defaultOrderParams: Partial<Order>;
- private readonly _privateKey: Buffer;
- constructor(privateKey: Buffer, defaultOrderParams: Partial<Order>) {
- this._defaultOrderParams = defaultOrderParams;
- this._privateKey = privateKey;
- }
- public async newSignedOrderAsync(
- customOrderParams: Partial<Order> = {},
- signatureType: SignatureType = SignatureType.EthSign,
- ): Promise<SignedOrder> {
- const tenMinutesInSeconds = 10 * 60;
- const currentBlockTimestamp = await getLatestBlockTimestampAsync();
- const order = ({
- senderAddress: constants.NULL_ADDRESS,
- expirationTimeSeconds: new BigNumber(currentBlockTimestamp).add(tenMinutesInSeconds),
- salt: generatePseudoRandomSalt(),
- takerAddress: constants.NULL_ADDRESS,
- ...this._defaultOrderParams,
- ...customOrderParams,
- } as any) as Order;
- const orderHashBuff = orderHashUtils.getOrderHashBuffer(order);
- const signature = signingUtils.signMessage(orderHashBuff, this._privateKey, signatureType);
- const signedOrder = {
- ...order,
- signature: `0x${signature.toString('hex')}`,
- };
- return signedOrder;
- }
-}
diff --git a/packages/contracts/test/utils/order_factory_from_scenario.ts b/packages/contracts/test/utils/order_factory_from_scenario.ts
deleted file mode 100644
index 60c8606c4..000000000
--- a/packages/contracts/test/utils/order_factory_from_scenario.ts
+++ /dev/null
@@ -1,296 +0,0 @@
-import { assetDataUtils, generatePseudoRandomSalt } from '@0x/order-utils';
-import { Order } from '@0x/types';
-import { BigNumber, errorUtils } from '@0x/utils';
-
-import { DummyERC721TokenContract } from '../../generated-wrappers/dummy_erc721_token';
-
-import { constants } from './constants';
-import {
- AssetDataScenario,
- ERC721TokenIdsByOwner,
- ExpirationTimeSecondsScenario,
- FeeRecipientAddressScenario,
- OrderAssetAmountScenario,
- OrderScenario,
- TakerScenario,
-} from './types';
-
-const TEN_UNITS_EIGHTEEN_DECIMALS = new BigNumber(10_000_000_000_000_000_000);
-const FIVE_UNITS_EIGHTEEN_DECIMALS = new BigNumber(5_000_000_000_000_000_000);
-const POINT_ONE_UNITS_EIGHTEEN_DECIMALS = new BigNumber(100_000_000_000_000_000);
-const POINT_ZERO_FIVE_UNITS_EIGHTEEN_DECIMALS = new BigNumber(50_000_000_000_000_000);
-const TEN_UNITS_FIVE_DECIMALS = new BigNumber(1_000_000);
-const FIVE_UNITS_FIVE_DECIMALS = new BigNumber(500_000);
-const TEN_UNITS_ZERO_DECIMALS = new BigNumber(10);
-const ONE_THOUSAND_UNITS_ZERO_DECIMALS = new BigNumber(1000);
-const ONE_NFT_UNIT = new BigNumber(1);
-
-export class OrderFactoryFromScenario {
- private readonly _userAddresses: string[];
- private readonly _zrxAddress: string;
- private readonly _nonZrxERC20EighteenDecimalTokenAddresses: string[];
- private readonly _erc20FiveDecimalTokenAddresses: string[];
- private readonly _erc20ZeroDecimalTokenAddresses: string[];
- private readonly _erc721Token: DummyERC721TokenContract;
- private readonly _erc721Balances: ERC721TokenIdsByOwner;
- private readonly _exchangeAddress: string;
- constructor(
- userAddresses: string[],
- zrxAddress: string,
- nonZrxERC20EighteenDecimalTokenAddresses: string[],
- erc20FiveDecimalTokenAddresses: string[],
- erc20ZeroDecimalTokenAddresses: string[],
- erc721Token: DummyERC721TokenContract,
- erc721Balances: ERC721TokenIdsByOwner,
- exchangeAddress: string,
- ) {
- this._userAddresses = userAddresses;
- this._zrxAddress = zrxAddress;
- this._nonZrxERC20EighteenDecimalTokenAddresses = nonZrxERC20EighteenDecimalTokenAddresses;
- this._erc20FiveDecimalTokenAddresses = erc20FiveDecimalTokenAddresses;
- this._erc20ZeroDecimalTokenAddresses = erc20ZeroDecimalTokenAddresses;
- this._erc721Token = erc721Token;
- this._erc721Balances = erc721Balances;
- this._exchangeAddress = exchangeAddress;
- }
- public generateOrder(orderScenario: OrderScenario): Order {
- const makerAddress = this._userAddresses[1];
- let takerAddress = this._userAddresses[2];
- const erc721MakerAssetIds = this._erc721Balances[makerAddress][this._erc721Token.address];
- const erc721TakerAssetIds = this._erc721Balances[takerAddress][this._erc721Token.address];
- let feeRecipientAddress;
- let makerAssetAmount;
- let takerAssetAmount;
- let makerFee;
- let takerFee;
- let expirationTimeSeconds;
- let makerAssetData;
- let takerAssetData;
-
- switch (orderScenario.feeRecipientScenario) {
- case FeeRecipientAddressScenario.BurnAddress:
- feeRecipientAddress = constants.NULL_ADDRESS;
- break;
- case FeeRecipientAddressScenario.EthUserAddress:
- feeRecipientAddress = this._userAddresses[4];
- break;
- default:
- throw errorUtils.spawnSwitchErr('FeeRecipientAddressScenario', orderScenario.feeRecipientScenario);
- }
-
- switch (orderScenario.makerAssetDataScenario) {
- case AssetDataScenario.ZRXFeeToken:
- makerAssetData = assetDataUtils.encodeERC20AssetData(this._zrxAddress);
- break;
- case AssetDataScenario.ERC20NonZRXEighteenDecimals:
- makerAssetData = assetDataUtils.encodeERC20AssetData(this._nonZrxERC20EighteenDecimalTokenAddresses[0]);
- break;
- case AssetDataScenario.ERC20FiveDecimals:
- makerAssetData = assetDataUtils.encodeERC20AssetData(this._erc20FiveDecimalTokenAddresses[0]);
- break;
- case AssetDataScenario.ERC721:
- makerAssetData = assetDataUtils.encodeERC721AssetData(
- this._erc721Token.address,
- erc721MakerAssetIds[0],
- );
- break;
- case AssetDataScenario.ERC20ZeroDecimals:
- makerAssetData = assetDataUtils.encodeERC20AssetData(this._erc20ZeroDecimalTokenAddresses[0]);
- break;
- default:
- throw errorUtils.spawnSwitchErr('AssetDataScenario', orderScenario.makerAssetDataScenario);
- }
-
- switch (orderScenario.takerAssetDataScenario) {
- case AssetDataScenario.ZRXFeeToken:
- takerAssetData = assetDataUtils.encodeERC20AssetData(this._zrxAddress);
- break;
- case AssetDataScenario.ERC20NonZRXEighteenDecimals:
- takerAssetData = assetDataUtils.encodeERC20AssetData(this._nonZrxERC20EighteenDecimalTokenAddresses[1]);
- break;
- case AssetDataScenario.ERC20FiveDecimals:
- takerAssetData = assetDataUtils.encodeERC20AssetData(this._erc20FiveDecimalTokenAddresses[1]);
- break;
- case AssetDataScenario.ERC721:
- takerAssetData = assetDataUtils.encodeERC721AssetData(
- this._erc721Token.address,
- erc721TakerAssetIds[0],
- );
- break;
- case AssetDataScenario.ERC20ZeroDecimals:
- takerAssetData = assetDataUtils.encodeERC20AssetData(this._erc20ZeroDecimalTokenAddresses[1]);
- break;
- default:
- throw errorUtils.spawnSwitchErr('AssetDataScenario', orderScenario.takerAssetDataScenario);
- }
-
- switch (orderScenario.makerAssetAmountScenario) {
- case OrderAssetAmountScenario.Large:
- switch (orderScenario.makerAssetDataScenario) {
- case AssetDataScenario.ZRXFeeToken:
- case AssetDataScenario.ERC20NonZRXEighteenDecimals:
- makerAssetAmount = TEN_UNITS_EIGHTEEN_DECIMALS;
- break;
- case AssetDataScenario.ERC20FiveDecimals:
- makerAssetAmount = TEN_UNITS_FIVE_DECIMALS;
- break;
- case AssetDataScenario.ERC721:
- makerAssetAmount = ONE_NFT_UNIT;
- break;
- case AssetDataScenario.ERC20ZeroDecimals:
- makerAssetAmount = ONE_THOUSAND_UNITS_ZERO_DECIMALS;
- break;
- default:
- throw errorUtils.spawnSwitchErr('AssetDataScenario', orderScenario.makerAssetDataScenario);
- }
- break;
- case OrderAssetAmountScenario.Small:
- switch (orderScenario.makerAssetDataScenario) {
- case AssetDataScenario.ZRXFeeToken:
- case AssetDataScenario.ERC20NonZRXEighteenDecimals:
- makerAssetAmount = FIVE_UNITS_EIGHTEEN_DECIMALS;
- break;
- case AssetDataScenario.ERC20FiveDecimals:
- makerAssetAmount = FIVE_UNITS_FIVE_DECIMALS;
- break;
- case AssetDataScenario.ERC721:
- makerAssetAmount = ONE_NFT_UNIT;
- break;
- case AssetDataScenario.ERC20ZeroDecimals:
- makerAssetAmount = TEN_UNITS_ZERO_DECIMALS;
- break;
- default:
- throw errorUtils.spawnSwitchErr('AssetDataScenario', orderScenario.makerAssetDataScenario);
- }
- break;
- case OrderAssetAmountScenario.Zero:
- makerAssetAmount = new BigNumber(0);
- break;
- default:
- throw errorUtils.spawnSwitchErr('OrderAssetAmountScenario', orderScenario.makerAssetAmountScenario);
- }
-
- switch (orderScenario.takerAssetAmountScenario) {
- case OrderAssetAmountScenario.Large:
- switch (orderScenario.takerAssetDataScenario) {
- case AssetDataScenario.ERC20NonZRXEighteenDecimals:
- case AssetDataScenario.ZRXFeeToken:
- takerAssetAmount = TEN_UNITS_EIGHTEEN_DECIMALS;
- break;
- case AssetDataScenario.ERC20FiveDecimals:
- takerAssetAmount = TEN_UNITS_FIVE_DECIMALS;
- break;
- case AssetDataScenario.ERC721:
- takerAssetAmount = ONE_NFT_UNIT;
- break;
- case AssetDataScenario.ERC20ZeroDecimals:
- takerAssetAmount = ONE_THOUSAND_UNITS_ZERO_DECIMALS;
- break;
- default:
- throw errorUtils.spawnSwitchErr('AssetDataScenario', orderScenario.takerAssetDataScenario);
- }
- break;
- case OrderAssetAmountScenario.Small:
- switch (orderScenario.takerAssetDataScenario) {
- case AssetDataScenario.ERC20NonZRXEighteenDecimals:
- case AssetDataScenario.ZRXFeeToken:
- takerAssetAmount = FIVE_UNITS_EIGHTEEN_DECIMALS;
- break;
- case AssetDataScenario.ERC20FiveDecimals:
- takerAssetAmount = FIVE_UNITS_FIVE_DECIMALS;
- break;
- case AssetDataScenario.ERC721:
- takerAssetAmount = ONE_NFT_UNIT;
- break;
- case AssetDataScenario.ERC20ZeroDecimals:
- takerAssetAmount = TEN_UNITS_ZERO_DECIMALS;
- break;
- default:
- throw errorUtils.spawnSwitchErr('AssetDataScenario', orderScenario.takerAssetDataScenario);
- }
- break;
- case OrderAssetAmountScenario.Zero:
- takerAssetAmount = new BigNumber(0);
- break;
- default:
- throw errorUtils.spawnSwitchErr('OrderAssetAmountScenario', orderScenario.takerAssetAmountScenario);
- }
-
- switch (orderScenario.makerFeeScenario) {
- case OrderAssetAmountScenario.Large:
- makerFee = POINT_ONE_UNITS_EIGHTEEN_DECIMALS;
- break;
- case OrderAssetAmountScenario.Small:
- makerFee = POINT_ZERO_FIVE_UNITS_EIGHTEEN_DECIMALS;
- break;
- case OrderAssetAmountScenario.Zero:
- makerFee = new BigNumber(0);
- break;
- default:
- throw errorUtils.spawnSwitchErr('OrderAssetAmountScenario', orderScenario.makerFeeScenario);
- }
-
- switch (orderScenario.takerFeeScenario) {
- case OrderAssetAmountScenario.Large:
- takerFee = POINT_ONE_UNITS_EIGHTEEN_DECIMALS;
- break;
- case OrderAssetAmountScenario.Small:
- takerFee = POINT_ZERO_FIVE_UNITS_EIGHTEEN_DECIMALS;
- break;
- case OrderAssetAmountScenario.Zero:
- takerFee = new BigNumber(0);
- break;
- default:
- throw errorUtils.spawnSwitchErr('OrderAssetAmountScenario', orderScenario.takerFeeScenario);
- }
-
- switch (orderScenario.expirationTimeSecondsScenario) {
- case ExpirationTimeSecondsScenario.InFuture:
- expirationTimeSeconds = new BigNumber(2524604400); // Close to infinite
- break;
- case ExpirationTimeSecondsScenario.InPast:
- expirationTimeSeconds = new BigNumber(0); // Jan 1, 1970
- break;
- default:
- throw errorUtils.spawnSwitchErr(
- 'ExpirationTimeSecondsScenario',
- orderScenario.expirationTimeSecondsScenario,
- );
- }
-
- switch (orderScenario.takerScenario) {
- case TakerScenario.CorrectlySpecified:
- break; // noop since takerAddress is already specified
-
- case TakerScenario.IncorrectlySpecified:
- const notTaker = this._userAddresses[3];
- takerAddress = notTaker;
- break;
-
- case TakerScenario.Unspecified:
- takerAddress = constants.NULL_ADDRESS;
- break;
-
- default:
- throw errorUtils.spawnSwitchErr('TakerScenario', orderScenario.takerScenario);
- }
-
- const order = {
- senderAddress: constants.NULL_ADDRESS,
- makerAddress,
- takerAddress,
- makerFee,
- takerFee,
- makerAssetAmount,
- takerAssetAmount,
- makerAssetData,
- takerAssetData,
- salt: generatePseudoRandomSalt(),
- exchangeAddress: this._exchangeAddress,
- feeRecipientAddress,
- expirationTimeSeconds,
- };
-
- return order;
- }
-}
diff --git a/packages/contracts/test/utils/order_utils.ts b/packages/contracts/test/utils/order_utils.ts
deleted file mode 100644
index 4f7a34011..000000000
--- a/packages/contracts/test/utils/order_utils.ts
+++ /dev/null
@@ -1,58 +0,0 @@
-import { OrderWithoutExchangeAddress, SignedOrder } from '@0x/types';
-import { BigNumber } from '@0x/utils';
-
-import { constants } from './constants';
-import { CancelOrder, MatchOrder } from './types';
-
-export const orderUtils = {
- getPartialAmountFloor(numerator: BigNumber, denominator: BigNumber, target: BigNumber): BigNumber {
- const partialAmount = numerator
- .mul(target)
- .div(denominator)
- .floor();
- return partialAmount;
- },
- createFill: (signedOrder: SignedOrder, takerAssetFillAmount?: BigNumber) => {
- const fill = {
- order: orderUtils.getOrderWithoutExchangeAddress(signedOrder),
- takerAssetFillAmount: takerAssetFillAmount || signedOrder.takerAssetAmount,
- signature: signedOrder.signature,
- };
- return fill;
- },
- createCancel(signedOrder: SignedOrder, takerAssetCancelAmount?: BigNumber): CancelOrder {
- const cancel = {
- order: orderUtils.getOrderWithoutExchangeAddress(signedOrder),
- takerAssetCancelAmount: takerAssetCancelAmount || signedOrder.takerAssetAmount,
- };
- return cancel;
- },
- getOrderWithoutExchangeAddress(signedOrder: SignedOrder): OrderWithoutExchangeAddress {
- const orderStruct = {
- senderAddress: signedOrder.senderAddress,
- makerAddress: signedOrder.makerAddress,
- takerAddress: signedOrder.takerAddress,
- feeRecipientAddress: signedOrder.feeRecipientAddress,
- makerAssetAmount: signedOrder.makerAssetAmount,
- takerAssetAmount: signedOrder.takerAssetAmount,
- makerFee: signedOrder.makerFee,
- takerFee: signedOrder.takerFee,
- expirationTimeSeconds: signedOrder.expirationTimeSeconds,
- salt: signedOrder.salt,
- makerAssetData: signedOrder.makerAssetData,
- takerAssetData: signedOrder.takerAssetData,
- };
- return orderStruct;
- },
- createMatchOrders(signedOrderLeft: SignedOrder, signedOrderRight: SignedOrder): MatchOrder {
- const fill = {
- left: orderUtils.getOrderWithoutExchangeAddress(signedOrderLeft),
- right: orderUtils.getOrderWithoutExchangeAddress(signedOrderRight),
- leftSignature: signedOrderLeft.signature,
- rightSignature: signedOrderRight.signature,
- };
- fill.right.makerAssetData = constants.NULL_BYTES;
- fill.right.takerAssetData = constants.NULL_BYTES;
- return fill;
- },
-};
diff --git a/packages/contracts/test/utils/profiler.ts b/packages/contracts/test/utils/profiler.ts
deleted file mode 100644
index 2c7c1d66c..000000000
--- a/packages/contracts/test/utils/profiler.ts
+++ /dev/null
@@ -1,27 +0,0 @@
-import { devConstants } from '@0x/dev-utils';
-import { ProfilerSubprovider, SolCompilerArtifactAdapter } from '@0x/sol-cov';
-import * as _ from 'lodash';
-
-let profilerSubprovider: ProfilerSubprovider;
-
-export const profiler = {
- start(): void {
- profiler.getProfilerSubproviderSingleton().start();
- },
- stop(): void {
- profiler.getProfilerSubproviderSingleton().stop();
- },
- getProfilerSubproviderSingleton(): ProfilerSubprovider {
- if (_.isUndefined(profilerSubprovider)) {
- profilerSubprovider = profiler._getProfilerSubprovider();
- }
- return profilerSubprovider;
- },
- _getProfilerSubprovider(): ProfilerSubprovider {
- const defaultFromAddress = devConstants.TESTRPC_FIRST_ADDRESS;
- const solCompilerArtifactAdapter = new SolCompilerArtifactAdapter();
- const isVerbose = true;
- const subprovider = new ProfilerSubprovider(solCompilerArtifactAdapter, defaultFromAddress, isVerbose);
- return subprovider;
- },
-};
diff --git a/packages/contracts/test/utils/revert_trace.ts b/packages/contracts/test/utils/revert_trace.ts
deleted file mode 100644
index 3f74fd28b..000000000
--- a/packages/contracts/test/utils/revert_trace.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-import { devConstants } from '@0x/dev-utils';
-import { RevertTraceSubprovider, SolCompilerArtifactAdapter } from '@0x/sol-cov';
-import * as _ from 'lodash';
-
-let revertTraceSubprovider: RevertTraceSubprovider;
-
-export const revertTrace = {
- getRevertTraceSubproviderSingleton(): RevertTraceSubprovider {
- if (_.isUndefined(revertTraceSubprovider)) {
- revertTraceSubprovider = revertTrace._getRevertTraceSubprovider();
- }
- return revertTraceSubprovider;
- },
- _getRevertTraceSubprovider(): RevertTraceSubprovider {
- const defaultFromAddress = devConstants.TESTRPC_FIRST_ADDRESS;
- const solCompilerArtifactAdapter = new SolCompilerArtifactAdapter();
- const isVerbose = true;
- const subprovider = new RevertTraceSubprovider(solCompilerArtifactAdapter, defaultFromAddress, isVerbose);
- return subprovider;
- },
-};
diff --git a/packages/contracts/test/utils/signing_utils.ts b/packages/contracts/test/utils/signing_utils.ts
deleted file mode 100644
index 21f864bfa..000000000
--- a/packages/contracts/test/utils/signing_utils.ts
+++ /dev/null
@@ -1,29 +0,0 @@
-import { SignatureType } from '@0x/types';
-import * as ethUtil from 'ethereumjs-util';
-
-export const signingUtils = {
- signMessage(message: Buffer, privateKey: Buffer, signatureType: SignatureType): Buffer {
- if (signatureType === SignatureType.EthSign) {
- const prefixedMessage = ethUtil.hashPersonalMessage(message);
- const ecSignature = ethUtil.ecsign(prefixedMessage, privateKey);
- const signature = Buffer.concat([
- ethUtil.toBuffer(ecSignature.v),
- ecSignature.r,
- ecSignature.s,
- ethUtil.toBuffer(signatureType),
- ]);
- return signature;
- } else if (signatureType === SignatureType.EIP712) {
- const ecSignature = ethUtil.ecsign(message, privateKey);
- const signature = Buffer.concat([
- ethUtil.toBuffer(ecSignature.v),
- ecSignature.r,
- ecSignature.s,
- ethUtil.toBuffer(signatureType),
- ]);
- return signature;
- } else {
- throw new Error(`${signatureType} is not a valid signature type`);
- }
- },
-};
diff --git a/packages/contracts/test/utils/simple_asset_balance_and_proxy_allowance_fetcher.ts b/packages/contracts/test/utils/simple_asset_balance_and_proxy_allowance_fetcher.ts
deleted file mode 100644
index 64b7dedbe..000000000
--- a/packages/contracts/test/utils/simple_asset_balance_and_proxy_allowance_fetcher.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-import { AbstractBalanceAndProxyAllowanceFetcher } from '@0x/order-utils';
-import { BigNumber } from '@0x/utils';
-
-import { AssetWrapper } from './asset_wrapper';
-
-export class SimpleAssetBalanceAndProxyAllowanceFetcher implements AbstractBalanceAndProxyAllowanceFetcher {
- private readonly _assetWrapper: AssetWrapper;
- constructor(assetWrapper: AssetWrapper) {
- this._assetWrapper = assetWrapper;
- }
- public async getBalanceAsync(assetData: string, userAddress: string): Promise<BigNumber> {
- const balance = await this._assetWrapper.getBalanceAsync(userAddress, assetData);
- return balance;
- }
- public async getProxyAllowanceAsync(assetData: string, userAddress: string): Promise<BigNumber> {
- const proxyAllowance = await this._assetWrapper.getProxyAllowanceAsync(userAddress, assetData);
- return proxyAllowance;
- }
-}
diff --git a/packages/contracts/test/utils/simple_order_filled_cancelled_fetcher.ts b/packages/contracts/test/utils/simple_order_filled_cancelled_fetcher.ts
deleted file mode 100644
index af959e00e..000000000
--- a/packages/contracts/test/utils/simple_order_filled_cancelled_fetcher.ts
+++ /dev/null
@@ -1,31 +0,0 @@
-import { AbstractOrderFilledCancelledFetcher, orderHashUtils } from '@0x/order-utils';
-import { SignedOrder } from '@0x/types';
-import { BigNumber } from '@0x/utils';
-
-import { ExchangeWrapper } from './exchange_wrapper';
-
-export class SimpleOrderFilledCancelledFetcher implements AbstractOrderFilledCancelledFetcher {
- private readonly _exchangeWrapper: ExchangeWrapper;
- private readonly _zrxAssetData: string;
- constructor(exchange: ExchangeWrapper, zrxAssetData: string) {
- this._exchangeWrapper = exchange;
- this._zrxAssetData = zrxAssetData;
- }
- public async getFilledTakerAmountAsync(orderHash: string): Promise<BigNumber> {
- const filledTakerAmount = new BigNumber(await this._exchangeWrapper.getTakerAssetFilledAmountAsync(orderHash));
- return filledTakerAmount;
- }
- public async isOrderCancelledAsync(signedOrder: SignedOrder): Promise<boolean> {
- const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
- const isCancelled = await this._exchangeWrapper.isCancelledAsync(orderHash);
- const orderEpoch = await this._exchangeWrapper.getOrderEpochAsync(
- signedOrder.makerAddress,
- signedOrder.senderAddress,
- );
- const isCancelledByOrderEpoch = orderEpoch > signedOrder.salt;
- return isCancelled || isCancelledByOrderEpoch;
- }
- public getZRXAssetData(): string {
- return this._zrxAssetData;
- }
-}
diff --git a/packages/contracts/test/utils/test_with_reference.ts b/packages/contracts/test/utils/test_with_reference.ts
deleted file mode 100644
index b80be4a6c..000000000
--- a/packages/contracts/test/utils/test_with_reference.ts
+++ /dev/null
@@ -1,139 +0,0 @@
-import * as chai from 'chai';
-import * as _ from 'lodash';
-
-import { chaiSetup } from './chai_setup';
-
-chaiSetup.configure();
-const expect = chai.expect;
-
-class Value<T> {
- public value: T;
- constructor(value: T) {
- this.value = value;
- }
-}
-
-// tslint:disable-next-line: max-classes-per-file
-class ErrorMessage {
- public error: string;
- constructor(message: string) {
- this.error = message;
- }
-}
-
-type PromiseResult<T> = Value<T> | ErrorMessage;
-
-// TODO(albrow): This seems like a generic utility function that could exist in
-// lodash. We should replace it by a library implementation, or move it to our
-// own.
-async function evaluatePromise<T>(promise: Promise<T>): Promise<PromiseResult<T>> {
- try {
- return new Value<T>(await promise);
- } catch (e) {
- return new ErrorMessage(e.message);
- }
-}
-
-export async function testWithReferenceFuncAsync<P0, R>(
- referenceFunc: (p0: P0) => Promise<R>,
- testFunc: (p0: P0) => Promise<R>,
- values: [P0],
-): Promise<void>;
-export async function testWithReferenceFuncAsync<P0, P1, R>(
- referenceFunc: (p0: P0, p1: P1) => Promise<R>,
- testFunc: (p0: P0, p1: P1) => Promise<R>,
- values: [P0, P1],
-): Promise<void>;
-export async function testWithReferenceFuncAsync<P0, P1, P2, R>(
- referenceFunc: (p0: P0, p1: P1, p2: P2) => Promise<R>,
- testFunc: (p0: P0, p1: P1, p2: P2) => Promise<R>,
- values: [P0, P1, P2],
-): Promise<void>;
-export async function testWithReferenceFuncAsync<P0, P1, P2, P3, R>(
- referenceFunc: (p0: P0, p1: P1, p2: P2, p3: P3) => Promise<R>,
- testFunc: (p0: P0, p1: P1, p2: P2, p3: P3) => Promise<R>,
- values: [P0, P1, P2, P3],
-): Promise<void>;
-export async function testWithReferenceFuncAsync<P0, P1, P2, P3, P4, R>(
- referenceFunc: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4) => Promise<R>,
- testFunc: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4) => Promise<R>,
- values: [P0, P1, P2, P3, P4],
-): Promise<void>;
-
-/**
- * Tests the behavior of a test function by comparing it to the expected
- * behavior (defined by a reference function).
- *
- * First the reference function will be called to obtain an "expected result",
- * or if the reference function throws/rejects, an "expected error". Next, the
- * test function will be called to obtain an "actual result", or if the test
- * function throws/rejects, an "actual error". The test passes if at least one
- * of the following conditions is met:
- *
- * 1) Neither the reference function or the test function throw and the
- * "expected result" equals the "actual result".
- *
- * 2) Both the reference function and the test function throw and the "actual
- * error" message *contains* the "expected error" message.
- *
- * @param referenceFuncAsync a reference function implemented in pure
- * JavaScript/TypeScript which accepts N arguments and returns the "expected
- * result" or throws/rejects with the "expected error".
- * @param testFuncAsync a test function which, e.g., makes a call or sends a
- * transaction to a contract. It accepts the same N arguments returns the
- * "actual result" or throws/rejects with the "actual error".
- * @param values an array of N values, where each value corresponds in-order to
- * an argument to both the test function and the reference function.
- * @return A Promise that resolves if the test passes and rejects if the test
- * fails, according to the rules described above.
- */
-export async function testWithReferenceFuncAsync(
- referenceFuncAsync: (...args: any[]) => Promise<any>,
- testFuncAsync: (...args: any[]) => Promise<any>,
- values: any[],
-): Promise<void> {
- // Measure correct behaviour
- const expected = await evaluatePromise(referenceFuncAsync(...values));
-
- // Measure actual behaviour
- const actual = await evaluatePromise(testFuncAsync(...values));
-
- // Compare behaviour
- if (expected instanceof ErrorMessage) {
- // If we expected an error, check if the actual error message contains the
- // expected error message.
- if (!(actual instanceof ErrorMessage)) {
- throw new Error(
- `Expected error containing ${expected.error} but got no error\n\tTest case: ${_getTestCaseString(
- referenceFuncAsync,
- values,
- )}`,
- );
- }
- expect(actual.error).to.contain(
- expected.error,
- `${actual.error}\n\tTest case: ${_getTestCaseString(referenceFuncAsync, values)}`,
- );
- } else {
- // If we do not expect an error, compare actual and expected directly.
- expect(actual).to.deep.equal(expected, `Test case ${_getTestCaseString(referenceFuncAsync, values)}`);
- }
-}
-
-function _getTestCaseString(referenceFuncAsync: (...args: any[]) => Promise<any>, values: any[]): string {
- const paramNames = _getParameterNames(referenceFuncAsync);
- return JSON.stringify(_.zipObject(paramNames, values));
-}
-
-// Source: https://stackoverflow.com/questions/1007981/how-to-get-function-parameter-names-values-dynamically
-function _getParameterNames(func: (...args: any[]) => any): string[] {
- return _.toString(func)
- .replace(/[/][/].*$/gm, '') // strip single-line comments
- .replace(/\s+/g, '') // strip white space
- .replace(/[/][*][^/*]*[*][/]/g, '') // strip multi-line comments
- .split('){', 1)[0]
- .replace(/^[^(]*[(]/, '') // extract the parameters
- .replace(/=[^,]+/g, '') // strip any ES6 defaults
- .split(',')
- .filter(Boolean); // split & filter [""]
-}
diff --git a/packages/contracts/test/utils/transaction_factory.ts b/packages/contracts/test/utils/transaction_factory.ts
deleted file mode 100644
index dbab3ade4..000000000
--- a/packages/contracts/test/utils/transaction_factory.ts
+++ /dev/null
@@ -1,37 +0,0 @@
-import { eip712Utils, generatePseudoRandomSalt } from '@0x/order-utils';
-import { SignatureType } from '@0x/types';
-import { signTypedDataUtils } from '@0x/utils';
-import * as ethUtil from 'ethereumjs-util';
-
-import { signingUtils } from './signing_utils';
-import { SignedTransaction } from './types';
-
-export class TransactionFactory {
- private readonly _signerBuff: Buffer;
- private readonly _exchangeAddress: string;
- private readonly _privateKey: Buffer;
- constructor(privateKey: Buffer, exchangeAddress: string) {
- this._privateKey = privateKey;
- this._exchangeAddress = exchangeAddress;
- this._signerBuff = ethUtil.privateToAddress(this._privateKey);
- }
- public newSignedTransaction(data: string, signatureType: SignatureType = SignatureType.EthSign): SignedTransaction {
- const salt = generatePseudoRandomSalt();
- const signerAddress = `0x${this._signerBuff.toString('hex')}`;
- const executeTransactionData = {
- salt,
- signerAddress,
- data,
- };
-
- const typedData = eip712Utils.createZeroExTransactionTypedData(executeTransactionData, this._exchangeAddress);
- const eip712MessageBuffer = signTypedDataUtils.generateTypedDataHash(typedData);
- const signature = signingUtils.signMessage(eip712MessageBuffer, this._privateKey, signatureType);
- const signedTx = {
- exchangeAddress: this._exchangeAddress,
- signature: `0x${signature.toString('hex')}`,
- ...executeTransactionData,
- };
- return signedTx;
- }
-}
diff --git a/packages/contracts/test/utils/type_encoding_utils.ts b/packages/contracts/test/utils/type_encoding_utils.ts
deleted file mode 100644
index bfd9c9ef5..000000000
--- a/packages/contracts/test/utils/type_encoding_utils.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-import { BigNumber } from '@0x/utils';
-import BN = require('bn.js');
-import ethUtil = require('ethereumjs-util');
-
-import { constants } from './constants';
-
-export const typeEncodingUtils = {
- encodeUint256(value: BigNumber): Buffer {
- const base = 10;
- const formattedValue = new BN(value.toString(base));
- const encodedValue = ethUtil.toBuffer(formattedValue);
- // tslint:disable-next-line:custom-no-magic-numbers
- const paddedValue = ethUtil.setLengthLeft(encodedValue, constants.WORD_LENGTH);
- return paddedValue;
- },
- decodeUint256(encodedValue: Buffer): BigNumber {
- const formattedValue = ethUtil.bufferToHex(encodedValue);
- const value = new BigNumber(formattedValue, constants.BASE_16);
- return value;
- },
-};
diff --git a/packages/contracts/test/utils/types.ts b/packages/contracts/test/utils/types.ts
deleted file mode 100644
index 9fc9e1570..000000000
--- a/packages/contracts/test/utils/types.ts
+++ /dev/null
@@ -1,241 +0,0 @@
-import { OrderWithoutExchangeAddress } from '@0x/types';
-import { BigNumber } from '@0x/utils';
-import { AbiDefinition } from 'ethereum-types';
-
-export interface ERC20BalancesByOwner {
- [ownerAddress: string]: {
- [tokenAddress: string]: BigNumber;
- };
-}
-
-export interface ERC721TokenIdsByOwner {
- [ownerAddress: string]: {
- [tokenAddress: string]: BigNumber[];
- };
-}
-
-export interface SubmissionContractEventArgs {
- transactionId: BigNumber;
-}
-
-export interface BatchFillOrders {
- orders: OrderWithoutExchangeAddress[];
- signatures: string[];
- takerAssetFillAmounts: BigNumber[];
-}
-
-export interface MarketSellOrders {
- orders: OrderWithoutExchangeAddress[];
- signatures: string[];
- takerAssetFillAmount: BigNumber;
-}
-
-export interface MarketBuyOrders {
- orders: OrderWithoutExchangeAddress[];
- signatures: string[];
- makerAssetFillAmount: BigNumber;
-}
-
-export interface BatchCancelOrders {
- orders: OrderWithoutExchangeAddress[];
-}
-
-export interface CancelOrdersBefore {
- salt: BigNumber;
-}
-
-export interface TransactionDataParams {
- name: string;
- abi: AbiDefinition[];
- args: any[];
-}
-
-export interface MultiSigConfig {
- owners: string[];
- confirmationsRequired: number;
- secondsRequired: number;
-}
-
-export interface MultiSigConfigByNetwork {
- [networkName: string]: MultiSigConfig;
-}
-
-export interface Token {
- address?: string;
- name: string;
- symbol: string;
- decimals: number;
- ipfsHash: string;
- swarmHash: string;
-}
-
-export enum OrderStatus {
- INVALID,
- INVALID_MAKER_ASSET_AMOUNT,
- INVALID_TAKER_ASSET_AMOUNT,
- FILLABLE,
- EXPIRED,
- FULLY_FILLED,
- CANCELLED,
-}
-
-export enum ContractName {
- TokenRegistry = 'TokenRegistry',
- MultiSigWalletWithTimeLock = 'MultiSigWalletWithTimeLock',
- Exchange = 'Exchange',
- ZRXToken = 'ZRXToken',
- DummyERC20Token = 'DummyERC20Token',
- EtherToken = 'WETH9',
- AssetProxyOwner = 'AssetProxyOwner',
- AccountLevels = 'AccountLevels',
- EtherDelta = 'EtherDelta',
- Arbitrage = 'Arbitrage',
- TestAssetDataDecoders = 'TestAssetDataDecoders',
- TestAssetProxyDispatcher = 'TestAssetProxyDispatcher',
- TestLibs = 'TestLibs',
- TestSignatureValidator = 'TestSignatureValidator',
- ERC20Proxy = 'ERC20Proxy',
- ERC721Proxy = 'ERC721Proxy',
- DummyERC721Receiver = 'DummyERC721Receiver',
- DummyERC721Token = 'DummyERC721Token',
- TestLibBytes = 'TestLibBytes',
- TestWallet = 'TestWallet',
- Authorizable = 'Authorizable',
- Whitelist = 'Whitelist',
- Forwarder = 'Forwarder',
-}
-
-export interface SignedTransaction {
- exchangeAddress: string;
- salt: BigNumber;
- signerAddress: string;
- data: string;
- signature: string;
-}
-
-export interface TransferAmountsByMatchOrders {
- // Left Maker
- amountBoughtByLeftMaker: BigNumber;
- amountSoldByLeftMaker: BigNumber;
- feePaidByLeftMaker: BigNumber;
- // Right Maker
- amountBoughtByRightMaker: BigNumber;
- amountSoldByRightMaker: BigNumber;
- feePaidByRightMaker: BigNumber;
- // Taker
- amountReceivedByTaker: BigNumber;
- feePaidByTakerLeft: BigNumber;
- feePaidByTakerRight: BigNumber;
-}
-
-export interface TransferAmountsLoggedByMatchOrders {
- makerAddress: string;
- takerAddress: string;
- makerAssetFilledAmount: string;
- takerAssetFilledAmount: string;
- makerFeePaid: string;
- takerFeePaid: string;
-}
-
-export interface OrderInfo {
- orderStatus: number;
- orderHash: string;
- orderTakerAssetFilledAmount: BigNumber;
-}
-
-export interface CancelOrder {
- order: OrderWithoutExchangeAddress;
- takerAssetCancelAmount: BigNumber;
-}
-
-export interface MatchOrder {
- left: OrderWithoutExchangeAddress;
- right: OrderWithoutExchangeAddress;
- leftSignature: string;
- rightSignature: string;
-}
-
-// Combinatorial testing types
-
-export enum FeeRecipientAddressScenario {
- BurnAddress = 'BURN_ADDRESS',
- EthUserAddress = 'ETH_USER_ADDRESS',
-}
-
-export enum OrderAssetAmountScenario {
- Zero = 'ZERO',
- Large = 'LARGE',
- Small = 'SMALL',
-}
-
-export enum TakerScenario {
- CorrectlySpecified = 'CORRECTLY_SPECIFIED',
- IncorrectlySpecified = 'INCORRECTLY_SPECIFIED',
- Unspecified = 'UNSPECIFIED',
-}
-
-export enum ExpirationTimeSecondsScenario {
- InPast = 'IN_PAST',
- InFuture = 'IN_FUTURE',
-}
-
-export enum AssetDataScenario {
- ERC20ZeroDecimals = 'ERC20_ZERO_DECIMALS',
- ZRXFeeToken = 'ZRX_FEE_TOKEN',
- ERC20FiveDecimals = 'ERC20_FIVE_DECIMALS',
- ERC20NonZRXEighteenDecimals = 'ERC20_NON_ZRX_EIGHTEEN_DECIMALS',
- ERC721 = 'ERC721',
-}
-
-export enum TakerAssetFillAmountScenario {
- Zero = 'ZERO',
- GreaterThanRemainingFillableTakerAssetAmount = 'GREATER_THAN_REMAINING_FILLABLE_TAKER_ASSET_AMOUNT',
- LessThanRemainingFillableTakerAssetAmount = 'LESS_THAN_REMAINING_FILLABLE_TAKER_ASSET_AMOUNT',
- ExactlyRemainingFillableTakerAssetAmount = 'EXACTLY_REMAINING_FILLABLE_TAKER_ASSET_AMOUNT',
-}
-
-export interface OrderScenario {
- takerScenario: TakerScenario;
- feeRecipientScenario: FeeRecipientAddressScenario;
- makerAssetAmountScenario: OrderAssetAmountScenario;
- takerAssetAmountScenario: OrderAssetAmountScenario;
- makerFeeScenario: OrderAssetAmountScenario;
- takerFeeScenario: OrderAssetAmountScenario;
- expirationTimeSecondsScenario: ExpirationTimeSecondsScenario;
- makerAssetDataScenario: AssetDataScenario;
- takerAssetDataScenario: AssetDataScenario;
-}
-
-export enum BalanceAmountScenario {
- Exact = 'EXACT',
- TooLow = 'TOO_LOW',
- Higher = 'HIGHER',
-}
-
-export enum AllowanceAmountScenario {
- Exact = 'EXACT',
- TooLow = 'TOO_LOW',
- Higher = 'HIGHER',
- Unlimited = 'UNLIMITED',
-}
-
-export interface TraderStateScenario {
- traderAssetBalance: BalanceAmountScenario;
- traderAssetAllowance: AllowanceAmountScenario;
- zrxFeeBalance: BalanceAmountScenario;
- zrxFeeAllowance: AllowanceAmountScenario;
-}
-
-export interface FillScenario {
- orderScenario: OrderScenario;
- takerAssetFillAmountScenario: TakerAssetFillAmountScenario;
- makerStateScenario: TraderStateScenario;
- takerStateScenario: TraderStateScenario;
-}
-
-export interface FillResults {
- makerAssetFilledAmount: BigNumber;
- takerAssetFilledAmount: BigNumber;
- makerFeePaid: BigNumber;
- takerFeePaid: BigNumber;
-}
diff --git a/packages/contracts/test/utils/web3_wrapper.ts b/packages/contracts/test/utils/web3_wrapper.ts
deleted file mode 100644
index f7b1a732a..000000000
--- a/packages/contracts/test/utils/web3_wrapper.ts
+++ /dev/null
@@ -1,84 +0,0 @@
-import { devConstants, env, EnvVars, web3Factory } from '@0x/dev-utils';
-import { prependSubprovider, Web3ProviderEngine } from '@0x/subproviders';
-import { logUtils } from '@0x/utils';
-import { Web3Wrapper } from '@0x/web3-wrapper';
-import * as _ from 'lodash';
-
-import { coverage } from './coverage';
-import { profiler } from './profiler';
-import { revertTrace } from './revert_trace';
-
-enum ProviderType {
- Ganache = 'ganache',
- Geth = 'geth',
-}
-
-let testProvider: ProviderType;
-switch (process.env.TEST_PROVIDER) {
- case undefined:
- testProvider = ProviderType.Ganache;
- break;
- case 'ganache':
- testProvider = ProviderType.Ganache;
- break;
- case 'geth':
- testProvider = ProviderType.Geth;
- break;
- default:
- throw new Error(`Unknown TEST_PROVIDER: ${process.env.TEST_PROVIDER}`);
-}
-
-const ganacheTxDefaults = {
- from: devConstants.TESTRPC_FIRST_ADDRESS,
- gas: devConstants.GAS_LIMIT,
-};
-const gethTxDefaults = {
- from: devConstants.TESTRPC_FIRST_ADDRESS,
-};
-export const txDefaults = testProvider === ProviderType.Ganache ? ganacheTxDefaults : gethTxDefaults;
-
-const gethConfigs = {
- shouldUseInProcessGanache: false,
- rpcUrl: 'http://localhost:8501',
- shouldUseFakeGasEstimate: false,
-};
-const ganacheConfigs = {
- shouldUseInProcessGanache: true,
-};
-const providerConfigs = testProvider === ProviderType.Ganache ? ganacheConfigs : gethConfigs;
-
-export const provider: Web3ProviderEngine = web3Factory.getRpcProvider(providerConfigs);
-const isCoverageEnabled = env.parseBoolean(EnvVars.SolidityCoverage);
-const isProfilerEnabled = env.parseBoolean(EnvVars.SolidityProfiler);
-const isRevertTraceEnabled = env.parseBoolean(EnvVars.SolidityRevertTrace);
-const enabledSubproviderCount = _.filter(
- [isCoverageEnabled, isProfilerEnabled, isRevertTraceEnabled],
- _.identity.bind(_),
-).length;
-if (enabledSubproviderCount > 1) {
- throw new Error(`Only one of coverage, profiler, or revert trace subproviders can be enabled at a time`);
-}
-if (isCoverageEnabled) {
- const coverageSubprovider = coverage.getCoverageSubproviderSingleton();
- prependSubprovider(provider, coverageSubprovider);
-}
-if (isProfilerEnabled) {
- if (testProvider === ProviderType.Ganache) {
- logUtils.warn(
- "Gas costs in Ganache traces are incorrect and we don't recommend using it for profiling. Please switch to Geth",
- );
- process.exit(1);
- }
- const profilerSubprovider = profiler.getProfilerSubproviderSingleton();
- logUtils.log(
- "By default profilerSubprovider is stopped so that you don't get noise from setup code. Don't forget to start it before the code you want to profile and stop it afterwards",
- );
- profilerSubprovider.stop();
- prependSubprovider(provider, profilerSubprovider);
-}
-if (isRevertTraceEnabled) {
- const revertTraceSubprovider = revertTrace.getRevertTraceSubproviderSingleton();
- prependSubprovider(provider, revertTraceSubprovider);
-}
-
-export const web3Wrapper = new Web3Wrapper(provider);
diff --git a/packages/contracts/test/utils_test/test_with_reference.ts b/packages/contracts/test/utils_test/test_with_reference.ts
deleted file mode 100644
index 8d633cd1f..000000000
--- a/packages/contracts/test/utils_test/test_with_reference.ts
+++ /dev/null
@@ -1,63 +0,0 @@
-import * as chai from 'chai';
-
-import { chaiSetup } from '../utils/chai_setup';
-import { testWithReferenceFuncAsync } from '../utils/test_with_reference';
-
-chaiSetup.configure();
-const expect = chai.expect;
-
-async function divAsync(x: number, y: number): Promise<number> {
- if (y === 0) {
- throw new Error('MathError: divide by zero');
- }
- return x / y;
-}
-
-// returns an async function that always returns the given value.
-function alwaysValueFunc(value: number): (x: number, y: number) => Promise<number> {
- return async (x: number, y: number) => value;
-}
-
-// returns an async function which always throws/rejects with the given error
-// message.
-function alwaysFailFunc(errMessage: string): (x: number, y: number) => Promise<number> {
- return async (x: number, y: number) => {
- throw new Error(errMessage);
- };
-}
-
-describe('testWithReferenceFuncAsync', () => {
- it('passes when both succeed and actual === expected', async () => {
- await testWithReferenceFuncAsync(alwaysValueFunc(0.5), divAsync, [1, 2]);
- });
-
- it('passes when both fail and actual error contains expected error', async () => {
- await testWithReferenceFuncAsync(alwaysFailFunc('divide by zero'), divAsync, [1, 0]);
- });
-
- it('fails when both succeed and actual !== expected', async () => {
- expect(testWithReferenceFuncAsync(alwaysValueFunc(3), divAsync, [1, 2])).to.be.rejectedWith(
- 'Test case {"x":1,"y":2}: expected { value: 0.5 } to deeply equal { value: 3 }',
- );
- });
-
- it('fails when both fail and actual error does not contain expected error', async () => {
- expect(
- testWithReferenceFuncAsync(alwaysFailFunc('Unexpected math error'), divAsync, [1, 0]),
- ).to.be.rejectedWith(
- 'MathError: divide by zero\n\tTest case: {"x":1,"y":0}: expected \'MathError: divide by zero\' to include \'Unexpected math error\'',
- );
- });
-
- it('fails when referenceFunc succeeds and testFunc fails', async () => {
- expect(testWithReferenceFuncAsync(alwaysValueFunc(0), divAsync, [1, 0])).to.be.rejectedWith(
- 'Test case {"x":1,"y":0}: expected { error: \'MathError: divide by zero\' } to deeply equal { value: 0 }',
- );
- });
-
- it('fails when referenceFunc fails and testFunc succeeds', async () => {
- expect(testWithReferenceFuncAsync(alwaysFailFunc('divide by zero'), divAsync, [1, 2])).to.be.rejectedWith(
- 'Expected error containing divide by zero but got no error\n\tTest case: {"x":1,"y":2}',
- );
- });
-});
diff --git a/packages/contracts/tsconfig.json b/packages/contracts/tsconfig.json
deleted file mode 100644
index e0f85079a..000000000
--- a/packages/contracts/tsconfig.json
+++ /dev/null
@@ -1,49 +0,0 @@
-{
- "extends": "../../tsconfig",
- "compilerOptions": {
- "outDir": "lib",
- "rootDir": ".",
- "resolveJsonModule": true
- },
- "include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"],
- "files": [
- "./generated-artifacts/AssetProxyOwner.json",
- "./generated-artifacts/DummyERC20Token.json",
- "./generated-artifacts/DummyERC721Receiver.json",
- "./generated-artifacts/DummyERC721Token.json",
- "./generated-artifacts/DummyMultipleReturnERC20Token.json",
- "./generated-artifacts/DummyNoReturnERC20Token.json",
- "./generated-artifacts/ERC20Proxy.json",
- "./generated-artifacts/ERC20Token.json",
- "./generated-artifacts/ERC721Proxy.json",
- "./generated-artifacts/ERC721Token.json",
- "./generated-artifacts/Exchange.json",
- "./generated-artifacts/ExchangeWrapper.json",
- "./generated-artifacts/Forwarder.json",
- "./generated-artifacts/IAssetData.json",
- "./generated-artifacts/IAssetProxy.json",
- "./generated-artifacts/IValidator.json",
- "./generated-artifacts/IWallet.json",
- "./generated-artifacts/InvalidERC721Receiver.json",
- "./generated-artifacts/MixinAuthorizable.json",
- "./generated-artifacts/MultiAssetProxy.json",
- "./generated-artifacts/MultiSigWallet.json",
- "./generated-artifacts/MultiSigWalletWithTimeLock.json",
- "./generated-artifacts/OrderValidator.json",
- "./generated-artifacts/ReentrantERC20Token.json",
- "./generated-artifacts/TestAssetProxyDispatcher.json",
- "./generated-artifacts/TestAssetProxyOwner.json",
- "./generated-artifacts/TestConstants.json",
- "./generated-artifacts/TestExchangeInternals.json",
- "./generated-artifacts/TestLibBytes.json",
- "./generated-artifacts/TestLibs.json",
- "./generated-artifacts/TestSignatureValidator.json",
- "./generated-artifacts/TestStaticCallReceiver.json",
- "./generated-artifacts/Validator.json",
- "./generated-artifacts/WETH9.json",
- "./generated-artifacts/Wallet.json",
- "./generated-artifacts/Whitelist.json",
- "./generated-artifacts/ZRXToken.json"
- ],
- "exclude": ["./deploy/solc/solc_bin"]
-}
diff --git a/packages/contracts/tslint.json b/packages/contracts/tslint.json
deleted file mode 100644
index 1bb3ac2a2..000000000
--- a/packages/contracts/tslint.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "extends": ["@0x/tslint-config"],
- "rules": {
- "custom-no-magic-numbers": false
- }
-}