diff options
151 files changed, 2114 insertions, 425 deletions
diff --git a/.circleci/config.yml b/.circleci/config.yml index 0ab512f58..fe81054ac 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -40,7 +40,9 @@ jobs: - restore_cache: keys: - repo-{{ .Environment.CIRCLE_SHA1 }} - - run: yarn wsrun test:circleci contracts + - run: yarn wsrun test:circleci @0x/contracts-multisig + - run: yarn wsrun test:circleci @0x/contracts-utils + - run: yarn wsrun test:circleci @0x/contracts-core test-contracts-geth: docker: - image: circleci/node:9 @@ -52,7 +54,9 @@ jobs: - repo-{{ .Environment.CIRCLE_SHA1 }} # HACK(albrow): we need to sleep 10 seconds to ensure the devnet is # initialized - - run: sleep 10 && TEST_PROVIDER=geth yarn wsrun test contracts + - run: sleep 10 && TEST_PROVIDER=geth yarn wsrun test @0x/contracts-multisig + - run: TEST_PROVIDER=geth yarn wsrun test @0x/contracts-utils + - run: TEST_PROVIDER=geth yarn wsrun test @0x/contracts-core test-publish: resource_class: medium+ docker: @@ -81,6 +85,7 @@ jobs: - restore_cache: keys: - repo-{{ .Environment.CIRCLE_SHA1 }} + - run: yarn wsrun test:circleci @0x/contracts-test-utils - run: yarn wsrun test:circleci @0x/abi-gen - run: yarn wsrun test:circleci @0x/assert - run: yarn wsrun test:circleci @0x/base-contract diff --git a/.gitignore b/.gitignore index 0e483dc0a..6a82f3e26 100644 --- a/.gitignore +++ b/.gitignore @@ -80,12 +80,16 @@ packages/testnet-faucets/server/ # generated contract artifacts/ contracts/core/generated-artifacts/ +contracts/multisig/generated-artifacts/ +contracts/utils/generated-artifacts/ packages/sol-cov/test/fixtures/artifacts/ packages/metacoin/artifacts/ # generated contract wrappers packages/abi-gen-wrappers/wrappers contracts/core/generated-wrappers/ +contracts/multisig/generated-wrappers/ +contracts/utils/generated-wrappers/ packages/metacoin/src/contract_wrappers # solc-bin in sol-compiler diff --git a/.prettierignore b/.prettierignore index 9dbb83e27..9684a83b7 100644 --- a/.prettierignore +++ b/.prettierignore @@ -2,6 +2,10 @@ lib .nyc_output /contracts/core/generated-wrappers /contracts/core/generated-artifacts +/contracts/multisig/generated-wrappers +/contracts/multisig/generated-artifacts +/contracts/utils/generated-wrappers +/contracts/utils/generated-artifacts /packages/abi-gen-wrappers/src/generated-wrappers /packages/contract-artifacts/artifacts /python-packages/order_utils/src/zero_ex/contract_artifacts/artifacts diff --git a/CODEOWNERS b/CODEOWNERS index 346e42ac0..ca98ec19b 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -14,7 +14,7 @@ packages/website/ @BMillman19 @fragosti @fabioberger @steveklebanoff packages/abi-gen/ @LogvinovLeon packages/base-contract/ @LogvinovLeon packages/connect/ @fragosti -packages/contract_templates/ @LogvinovLeon +packages/abi-gen-templates/ @LogvinovLeon packages/contract-addresses/ @albrow packages/contract-artifacts/ @albrow packages/dev-utils/ @LogvinovLeon @fabioberger diff --git a/contracts/TESTING.md b/contracts/TESTING.md new file mode 100644 index 000000000..750b3c62c --- /dev/null +++ b/contracts/TESTING.md @@ -0,0 +1,48 @@ +# Contracts 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/contracts/core/README.md b/contracts/core/README.md index 97a2816ff..0004925c1 100644 --- a/contracts/core/README.md +++ b/contracts/core/README.md @@ -14,8 +14,6 @@ Contracts that make up and interact with version 2.0.0 of the protocol can be fo * 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) @@ -52,13 +50,13 @@ yarn install 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 +PKG=@0x/contracts-core yarn build ``` Or continuously rebuild on change: ```bash -PKG=contracts yarn watch +PKG=@0x/contracts-core yarn watch ``` ### Clean @@ -81,49 +79,4 @@ 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. +Contracts testing options like coverage, profiling, revert traces or backing node choosing - are described [here](../TESTING.md). diff --git a/contracts/core/compiler.json b/contracts/core/compiler.json index c824e4645..8d9732794 100644 --- a/contracts/core/compiler.json +++ b/contracts/core/compiler.json @@ -25,6 +25,7 @@ "DummyERC721Token", "DummyMultipleReturnERC20Token", "DummyNoReturnERC20Token", + "DutchAuction", "ERC20Proxy", "ERC20Token", "ERC721Token", @@ -39,14 +40,10 @@ "IWallet", "MixinAuthorizable", "MultiAssetProxy", - "MultiSigWallet", - "MultiSigWalletWithTimeLock", "OrderValidator", "ReentrantERC20Token", "TestAssetProxyOwner", "TestAssetProxyDispatcher", - "TestConstants", - "TestLibBytes", "TestLibs", "TestExchangeInternals", "TestSignatureValidator", diff --git a/contracts/core/contracts/examples/Wallet/Wallet.sol b/contracts/core/contracts/examples/Wallet/Wallet.sol index b75021a31..3738be841 100644 --- a/contracts/core/contracts/examples/Wallet/Wallet.sol +++ b/contracts/core/contracts/examples/Wallet/Wallet.sol @@ -19,7 +19,7 @@ pragma solidity 0.4.24; import "../../protocol/Exchange/interfaces/IWallet.sol"; -import "../../utils/LibBytes/LibBytes.sol"; +import "@0x/contracts-utils/contracts/utils/LibBytes/LibBytes.sol"; contract Wallet is diff --git a/contracts/core/contracts/examples/Whitelist/Whitelist.sol b/contracts/core/contracts/examples/Whitelist/Whitelist.sol index e4e25038c..61c21c095 100644 --- a/contracts/core/contracts/examples/Whitelist/Whitelist.sol +++ b/contracts/core/contracts/examples/Whitelist/Whitelist.sol @@ -21,7 +21,7 @@ pragma experimental ABIEncoderV2; import "../../protocol/Exchange/interfaces/IExchange.sol"; import "../../protocol/Exchange/libs/LibOrder.sol"; -import "../../utils/Ownable/Ownable.sol"; +import "@0x/contracts-utils/contracts/utils/Ownable/Ownable.sol"; contract Whitelist is diff --git a/contracts/core/contracts/extensions/DutchAuction/DutchAuction.sol b/contracts/core/contracts/extensions/DutchAuction/DutchAuction.sol new file mode 100644 index 000000000..dfd4c46dc --- /dev/null +++ b/contracts/core/contracts/extensions/DutchAuction/DutchAuction.sol @@ -0,0 +1,205 @@ +/* + + 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 "@0x/contracts-utils/contracts/utils/LibBytes/LibBytes.sol"; +import "@0x/contracts-utils/contracts/utils/SafeMath/SafeMath.sol"; + + +contract DutchAuction is + SafeMath +{ + using LibBytes for bytes; + + // solhint-disable var-name-mixedcase + IExchange internal EXCHANGE; + + struct AuctionDetails { + uint256 beginTimeSeconds; // Auction begin unix timestamp: sellOrder.makerAssetData + uint256 endTimeSeconds; // Auction end unix timestamp: sellOrder.expiryTimeSeconds + uint256 beginAmount; // Auction begin amount: sellOrder.makerAssetData + uint256 endAmount; // Auction end amount: sellOrder.takerAssetAmount + uint256 currentAmount; // Calculated amount given block.timestamp + uint256 currentTimeSeconds; // block.timestamp + } + + constructor (address _exchange) + public + { + EXCHANGE = IExchange(_exchange); + } + + /// @dev Matches the buy and sell orders at an amount given the following: the current block time, the auction + /// start time and the auction begin amount. The sell order is a an order at the lowest amount + /// at the end of the auction. Excess from the match is transferred to the seller. + /// Over time the price moves from beginAmount to endAmount given the current block.timestamp. + /// sellOrder.expiryTimeSeconds is the end time of the auction. + /// sellOrder.takerAssetAmount is the end amount of the auction (lowest possible amount). + /// sellOrder.makerAssetData is the ABI encoded Asset Proxy data with the following data appended + /// buyOrder.makerAssetData is the buyers bid on the auction, must meet the amount for the current block timestamp + /// (uint256 beginTimeSeconds, uint256 beginAmount). + /// This function reverts in the following scenarios: + /// * Auction has not started (auctionDetails.currentTimeSeconds < auctionDetails.beginTimeSeconds) + /// * Auction has expired (auctionDetails.endTimeSeconds < auctionDetails.currentTimeSeconds) + /// * Amount is invalid: Buy order amount is too low (buyOrder.makerAssetAmount < auctionDetails.currentAmount) + /// * Amount is invalid: Invalid begin amount (auctionDetails.beginAmount > auctionDetails.endAmount) + /// * Any failure in the 0x Match Orders + /// @param buyOrder The Buyer's order. This order is for the current expected price of the auction. + /// @param sellOrder The Seller's order. This order is for the lowest amount (at the end of the auction). + /// @param buySignature Proof that order was created by the buyer. + /// @param sellSignature Proof that order was created by the seller. + /// @return matchedFillResults amounts filled and fees paid by maker and taker of matched orders. + function matchOrders( + LibOrder.Order memory buyOrder, + LibOrder.Order memory sellOrder, + bytes memory buySignature, + bytes memory sellSignature + ) + public + returns (LibFillResults.MatchedFillResults memory matchedFillResults) + { + AuctionDetails memory auctionDetails = getAuctionDetails(sellOrder); + // Ensure the auction has not yet started + require( + auctionDetails.currentTimeSeconds >= auctionDetails.beginTimeSeconds, + "AUCTION_NOT_STARTED" + ); + // Ensure the auction has not expired. This will fail later in 0x but we can save gas by failing early + require( + sellOrder.expirationTimeSeconds > auctionDetails.currentTimeSeconds, + "AUCTION_EXPIRED" + ); + // Validate the buyer amount is greater than the current auction amount + require( + buyOrder.makerAssetAmount >= auctionDetails.currentAmount, + "INVALID_AMOUNT" + ); + // Match orders, maximally filling `buyOrder` + matchedFillResults = EXCHANGE.matchOrders( + buyOrder, + sellOrder, + buySignature, + sellSignature + ); + // The difference in sellOrder.takerAssetAmount and current amount is given as spread to the matcher + // This may include additional spread from the buyOrder.makerAssetAmount and the currentAmount. + // e.g currentAmount is 30, sellOrder.takerAssetAmount is 10 and buyOrder.makerAssetamount is 40. + // 10 (40-30) is returned to the buyer, 20 (30-10) sent to the seller and 10 has previously + // been transferred to the seller during matchOrders + uint256 leftMakerAssetSpreadAmount = matchedFillResults.leftMakerAssetSpreadAmount; + if (leftMakerAssetSpreadAmount > 0) { + // ERC20 Asset data itself is encoded as follows: + // + // | Area | Offset | Length | Contents | + // |----------|--------|---------|-------------------------------------| + // | Header | 0 | 4 | function selector | + // | Params | | 1 * 32 | function parameters: | + // | | 4 | 12 | 1. token address padding | + // | | 16 | 20 | 2. token address | + bytes memory assetData = sellOrder.takerAssetData; + address token = assetData.readAddress(16); + // Calculate the excess from the buy order. This can occur if the buyer sends in a higher + // amount than the calculated current amount + uint256 buyerExcessAmount = safeSub(buyOrder.makerAssetAmount, auctionDetails.currentAmount); + uint256 sellerExcessAmount = safeSub(leftMakerAssetSpreadAmount, buyerExcessAmount); + // Return the difference between auctionDetails.currentAmount and sellOrder.takerAssetAmount + // to the seller + if (sellerExcessAmount > 0) { + IERC20Token(token).transfer(sellOrder.makerAddress, sellerExcessAmount); + } + // Return the difference between buyOrder.makerAssetAmount and auctionDetails.currentAmount + // to the buyer + if (buyerExcessAmount > 0) { + IERC20Token(token).transfer(buyOrder.makerAddress, buyerExcessAmount); + } + } + return matchedFillResults; + } + + /// @dev Calculates the Auction Details for the given order + /// @param order The sell order + /// @return AuctionDetails + function getAuctionDetails( + LibOrder.Order memory order + ) + public + returns (AuctionDetails memory auctionDetails) + { + uint256 makerAssetDataLength = order.makerAssetData.length; + // It is unknown the encoded data of makerAssetData, we assume the last 64 bytes + // are the Auction Details encoding. + // Auction Details is encoded as follows: + // + // | Area | Offset | Length | Contents | + // |----------|--------|---------|-------------------------------------| + // | Params | | 2 * 32 | parameters: | + // | | -64 | 32 | 1. auction begin unix timestamp | + // | | -32 | 32 | 2. auction begin begin amount | + // ERC20 asset data length is 4+32, 64 for auction details results in min length 100 + require( + makerAssetDataLength >= 100, + "INVALID_ASSET_DATA" + ); + uint256 auctionBeginTimeSeconds = order.makerAssetData.readUint256(makerAssetDataLength - 64); + uint256 auctionBeginAmount = order.makerAssetData.readUint256(makerAssetDataLength - 32); + // Ensure the auction has a valid begin time + require( + order.expirationTimeSeconds > auctionBeginTimeSeconds, + "INVALID_BEGIN_TIME" + ); + uint256 auctionDurationSeconds = order.expirationTimeSeconds-auctionBeginTimeSeconds; + // Ensure the auction goes from high to low + uint256 minAmount = order.takerAssetAmount; + require( + auctionBeginAmount > minAmount, + "INVALID_AMOUNT" + ); + uint256 amountDelta = auctionBeginAmount-minAmount; + // solhint-disable-next-line not-rely-on-time + uint256 timestamp = block.timestamp; + auctionDetails.beginTimeSeconds = auctionBeginTimeSeconds; + auctionDetails.endTimeSeconds = order.expirationTimeSeconds; + auctionDetails.beginAmount = auctionBeginAmount; + auctionDetails.endAmount = minAmount; + auctionDetails.currentTimeSeconds = timestamp; + + uint256 remainingDurationSeconds = order.expirationTimeSeconds-timestamp; + if (timestamp < auctionBeginTimeSeconds) { + // If the auction has not yet begun the current amount is the auctionBeginAmount + auctionDetails.currentAmount = auctionBeginAmount; + } else if (timestamp >= order.expirationTimeSeconds) { + // If the auction has ended the current amount is the minAmount. + // Auction end time is guaranteed by 0x Exchange due to the order expiration + auctionDetails.currentAmount = minAmount; + } else { + auctionDetails.currentAmount = safeAdd( + minAmount, + safeDiv( + safeMul(remainingDurationSeconds, amountDelta), + auctionDurationSeconds + ) + ); + } + return auctionDetails; + } +} diff --git a/contracts/core/contracts/extensions/Forwarder/MixinAssets.sol b/contracts/core/contracts/extensions/Forwarder/MixinAssets.sol index 43efb5ff3..5f5f3456d 100644 --- a/contracts/core/contracts/extensions/Forwarder/MixinAssets.sol +++ b/contracts/core/contracts/extensions/Forwarder/MixinAssets.sol @@ -18,8 +18,8 @@ pragma solidity 0.4.24; -import "../../utils/LibBytes/LibBytes.sol"; -import "../../utils/Ownable/Ownable.sol"; +import "@0x/contracts-utils/contracts/utils/LibBytes/LibBytes.sol"; +import "@0x/contracts-utils/contracts/utils/Ownable/Ownable.sol"; import "../../tokens/ERC20Token/IERC20Token.sol"; import "../../tokens/ERC721Token/IERC721Token.sol"; import "./libs/LibConstants.sol"; diff --git a/contracts/core/contracts/extensions/Forwarder/MixinForwarderCore.sol b/contracts/core/contracts/extensions/Forwarder/MixinForwarderCore.sol index 54487f726..a5dd99225 100644 --- a/contracts/core/contracts/extensions/Forwarder/MixinForwarderCore.sol +++ b/contracts/core/contracts/extensions/Forwarder/MixinForwarderCore.sol @@ -24,7 +24,7 @@ import "./mixins/MWeth.sol"; import "./mixins/MAssets.sol"; import "./mixins/MExchangeWrapper.sol"; import "./interfaces/IForwarderCore.sol"; -import "../../utils/LibBytes/LibBytes.sol"; +import "@0x/contracts-utils/contracts/utils/LibBytes/LibBytes.sol"; import "../../protocol/Exchange/libs/LibOrder.sol"; import "../../protocol/Exchange/libs/LibFillResults.sol"; import "../../protocol/Exchange/libs/LibMath.sol"; diff --git a/contracts/core/contracts/extensions/Forwarder/libs/LibConstants.sol b/contracts/core/contracts/extensions/Forwarder/libs/LibConstants.sol index 704e42ce3..0f98ae595 100644 --- a/contracts/core/contracts/extensions/Forwarder/libs/LibConstants.sol +++ b/contracts/core/contracts/extensions/Forwarder/libs/LibConstants.sol @@ -18,7 +18,7 @@ pragma solidity 0.4.24; -import "../../../utils/LibBytes/LibBytes.sol"; +import "@0x/contracts-utils/contracts/utils/LibBytes/LibBytes.sol"; import "../../../protocol/Exchange/interfaces/IExchange.sol"; import "../../../tokens/EtherToken/IEtherToken.sol"; import "../../../tokens/ERC20Token/IERC20Token.sol"; diff --git a/contracts/core/contracts/extensions/OrderValidator/OrderValidator.sol b/contracts/core/contracts/extensions/OrderValidator/OrderValidator.sol index 3385d35ef..e3f4f6832 100644 --- a/contracts/core/contracts/extensions/OrderValidator/OrderValidator.sol +++ b/contracts/core/contracts/extensions/OrderValidator/OrderValidator.sol @@ -23,7 +23,7 @@ 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"; +import "@0x/contracts-utils/contracts/utils/LibBytes/LibBytes.sol"; contract OrderValidator { diff --git a/contracts/core/contracts/protocol/AssetProxy/MixinAuthorizable.sol b/contracts/core/contracts/protocol/AssetProxy/MixinAuthorizable.sol index fe9bbf848..08f9b94dc 100644 --- a/contracts/core/contracts/protocol/AssetProxy/MixinAuthorizable.sol +++ b/contracts/core/contracts/protocol/AssetProxy/MixinAuthorizable.sol @@ -18,7 +18,7 @@ pragma solidity 0.4.24; -import "../../utils/Ownable/Ownable.sol"; +import "@0x/contracts-utils/contracts/utils/Ownable/Ownable.sol"; import "./mixins/MAuthorizable.sol"; diff --git a/contracts/core/contracts/protocol/AssetProxy/interfaces/IAuthorizable.sol b/contracts/core/contracts/protocol/AssetProxy/interfaces/IAuthorizable.sol index ba1d4aa77..96ee05dee 100644 --- a/contracts/core/contracts/protocol/AssetProxy/interfaces/IAuthorizable.sol +++ b/contracts/core/contracts/protocol/AssetProxy/interfaces/IAuthorizable.sol @@ -18,7 +18,7 @@ pragma solidity 0.4.24; -import "../../../utils/Ownable/IOwnable.sol"; +import "@0x/contracts-utils/contracts/utils/Ownable/IOwnable.sol"; contract IAuthorizable is diff --git a/contracts/core/contracts/protocol/AssetProxyOwner/AssetProxyOwner.sol b/contracts/core/contracts/protocol/AssetProxyOwner/AssetProxyOwner.sol index edb788fab..bfc7b5a66 100644 --- a/contracts/core/contracts/protocol/AssetProxyOwner/AssetProxyOwner.sol +++ b/contracts/core/contracts/protocol/AssetProxyOwner/AssetProxyOwner.sol @@ -18,8 +18,8 @@ pragma solidity 0.4.24; -import "../../multisig/MultiSigWalletWithTimeLock.sol"; -import "../../utils/LibBytes/LibBytes.sol"; +import "@0x/contracts-multisig/contracts/multisig/MultiSigWalletWithTimeLock.sol"; +import "@0x/contracts-utils/contracts/utils/LibBytes/LibBytes.sol"; contract AssetProxyOwner is diff --git a/contracts/core/contracts/protocol/Exchange/MixinAssetProxyDispatcher.sol b/contracts/core/contracts/protocol/Exchange/MixinAssetProxyDispatcher.sol index 87b09b6b3..02aeb4a13 100644 --- a/contracts/core/contracts/protocol/Exchange/MixinAssetProxyDispatcher.sol +++ b/contracts/core/contracts/protocol/Exchange/MixinAssetProxyDispatcher.sol @@ -18,7 +18,7 @@ pragma solidity 0.4.24; -import "../../utils/Ownable/Ownable.sol"; +import "@0x/contracts-utils/contracts/utils/Ownable/Ownable.sol"; import "./mixins/MAssetProxyDispatcher.sol"; import "../AssetProxy/interfaces/IAssetProxy.sol"; diff --git a/contracts/core/contracts/protocol/Exchange/MixinExchangeCore.sol b/contracts/core/contracts/protocol/Exchange/MixinExchangeCore.sol index 736dcd0b1..da721f78f 100644 --- a/contracts/core/contracts/protocol/Exchange/MixinExchangeCore.sol +++ b/contracts/core/contracts/protocol/Exchange/MixinExchangeCore.sol @@ -19,7 +19,7 @@ pragma solidity 0.4.24; pragma experimental ABIEncoderV2; -import "../../utils/ReentrancyGuard/ReentrancyGuard.sol"; +import "@0x/contracts-utils/contracts/utils/ReentrancyGuard/ReentrancyGuard.sol"; import "./libs/LibConstants.sol"; import "./libs/LibFillResults.sol"; import "./libs/LibOrder.sol"; diff --git a/contracts/core/contracts/protocol/Exchange/MixinMatchOrders.sol b/contracts/core/contracts/protocol/Exchange/MixinMatchOrders.sol index b4f6bdb26..da1e9d270 100644 --- a/contracts/core/contracts/protocol/Exchange/MixinMatchOrders.sol +++ b/contracts/core/contracts/protocol/Exchange/MixinMatchOrders.sol @@ -14,7 +14,7 @@ pragma solidity 0.4.24; pragma experimental ABIEncoderV2; -import "../../utils/ReentrancyGuard/ReentrancyGuard.sol"; +import "@0x/contracts-utils/contracts/utils/ReentrancyGuard/ReentrancyGuard.sol"; import "./libs/LibConstants.sol"; import "./libs/LibMath.sol"; import "./libs/LibOrder.sol"; diff --git a/contracts/core/contracts/protocol/Exchange/MixinSignatureValidator.sol b/contracts/core/contracts/protocol/Exchange/MixinSignatureValidator.sol index 176e28351..711535aa8 100644 --- a/contracts/core/contracts/protocol/Exchange/MixinSignatureValidator.sol +++ b/contracts/core/contracts/protocol/Exchange/MixinSignatureValidator.sol @@ -18,8 +18,8 @@ pragma solidity 0.4.24; -import "../../utils/LibBytes/LibBytes.sol"; -import "../../utils/ReentrancyGuard/ReentrancyGuard.sol"; +import "@0x/contracts-utils/contracts/utils/LibBytes/LibBytes.sol"; +import "@0x/contracts-utils/contracts/utils/ReentrancyGuard/ReentrancyGuard.sol"; import "./mixins/MSignatureValidator.sol"; import "./mixins/MTransactions.sol"; import "./interfaces/IWallet.sol"; @@ -239,18 +239,18 @@ contract MixinSignatureValidator is view returns (bool isValid) { - bytes memory calldata = abi.encodeWithSelector( + bytes memory callData = abi.encodeWithSelector( IWallet(walletAddress).isValidSignature.selector, hash, signature ); assembly { - let cdStart := add(calldata, 32) + 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 + mload(callData), // length of input cdStart, // write output over input 32 // output size is 32 bytes ) @@ -288,19 +288,19 @@ contract MixinSignatureValidator is view returns (bool isValid) { - bytes memory calldata = abi.encodeWithSelector( + bytes memory callData = abi.encodeWithSelector( IValidator(signerAddress).isValidSignature.selector, hash, signerAddress, signature ); assembly { - let cdStart := add(calldata, 32) + 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 + mload(callData), // length of input cdStart, // write output over input 32 // output size is 32 bytes ) diff --git a/contracts/core/contracts/protocol/Exchange/MixinWrapperFunctions.sol b/contracts/core/contracts/protocol/Exchange/MixinWrapperFunctions.sol index cddff0e5f..415246358 100644 --- a/contracts/core/contracts/protocol/Exchange/MixinWrapperFunctions.sol +++ b/contracts/core/contracts/protocol/Exchange/MixinWrapperFunctions.sol @@ -19,7 +19,7 @@ pragma solidity 0.4.24; pragma experimental ABIEncoderV2; -import "../../utils/ReentrancyGuard/ReentrancyGuard.sol"; +import "@0x/contracts-utils/contracts/utils/ReentrancyGuard/ReentrancyGuard.sol"; import "./libs/LibMath.sol"; import "./libs/LibOrder.sol"; import "./libs/LibFillResults.sol"; diff --git a/contracts/core/contracts/protocol/Exchange/libs/LibFillResults.sol b/contracts/core/contracts/protocol/Exchange/libs/LibFillResults.sol index 659ae9a69..fbd9950bf 100644 --- a/contracts/core/contracts/protocol/Exchange/libs/LibFillResults.sol +++ b/contracts/core/contracts/protocol/Exchange/libs/LibFillResults.sol @@ -18,7 +18,7 @@ pragma solidity 0.4.24; -import "../../../utils/SafeMath/SafeMath.sol"; +import "@0x/contracts-utils/contracts/utils/SafeMath/SafeMath.sol"; contract LibFillResults is diff --git a/contracts/core/contracts/protocol/Exchange/libs/LibMath.sol b/contracts/core/contracts/protocol/Exchange/libs/LibMath.sol index c0b85ea10..b24876a9c 100644 --- a/contracts/core/contracts/protocol/Exchange/libs/LibMath.sol +++ b/contracts/core/contracts/protocol/Exchange/libs/LibMath.sol @@ -18,7 +18,7 @@ pragma solidity 0.4.24; -import "../../../utils/SafeMath/SafeMath.sol"; +import "@0x/contracts-utils/contracts/utils/SafeMath/SafeMath.sol"; contract LibMath is diff --git a/contracts/core/contracts/test/DummyERC20Token/DummyERC20Token.sol b/contracts/core/contracts/test/DummyERC20Token/DummyERC20Token.sol index 412c5d1ad..33028db0c 100644 --- a/contracts/core/contracts/test/DummyERC20Token/DummyERC20Token.sol +++ b/contracts/core/contracts/test/DummyERC20Token/DummyERC20Token.sol @@ -18,7 +18,7 @@ pragma solidity 0.4.24; -import "../../utils/Ownable/Ownable.sol"; +import "@0x/contracts-utils/contracts/utils/Ownable/Ownable.sol"; import "../../tokens/ERC20Token/MintableERC20Token.sol"; diff --git a/contracts/core/contracts/test/DummyERC721Token/DummyERC721Token.sol b/contracts/core/contracts/test/DummyERC721Token/DummyERC721Token.sol index ac9068d1d..4c978b2df 100644 --- a/contracts/core/contracts/test/DummyERC721Token/DummyERC721Token.sol +++ b/contracts/core/contracts/test/DummyERC721Token/DummyERC721Token.sol @@ -19,7 +19,7 @@ pragma solidity 0.4.24; import "../../tokens/ERC721Token/MintableERC721Token.sol"; -import "../../utils/Ownable/Ownable.sol"; +import "@0x/contracts-utils/contracts/utils/Ownable/Ownable.sol"; // solhint-disable no-empty-blocks diff --git a/contracts/core/contracts/test/ReentrantERC20Token/ReentrantERC20Token.sol b/contracts/core/contracts/test/ReentrantERC20Token/ReentrantERC20Token.sol index aa3bf9ab8..3e9091931 100644 --- a/contracts/core/contracts/test/ReentrantERC20Token/ReentrantERC20Token.sol +++ b/contracts/core/contracts/test/ReentrantERC20Token/ReentrantERC20Token.sol @@ -19,7 +19,7 @@ pragma solidity 0.4.24; pragma experimental ABIEncoderV2; -import "../../utils/LibBytes/LibBytes.sol"; +import "@0x/contracts-utils/contracts/utils/LibBytes/LibBytes.sol"; import "../../tokens/ERC20Token/ERC20Token.sol"; import "../../protocol/Exchange/interfaces/IExchange.sol"; import "../../protocol/Exchange/libs/LibOrder.sol"; diff --git a/contracts/core/contracts/tokens/ERC20Token/MintableERC20Token.sol b/contracts/core/contracts/tokens/ERC20Token/MintableERC20Token.sol index 9dc924422..58bccb5a1 100644 --- a/contracts/core/contracts/tokens/ERC20Token/MintableERC20Token.sol +++ b/contracts/core/contracts/tokens/ERC20Token/MintableERC20Token.sol @@ -18,7 +18,7 @@ pragma solidity 0.4.24; -import "../../utils/SafeMath/SafeMath.sol"; +import "@0x/contracts-utils/contracts/utils/SafeMath/SafeMath.sol"; import "./UnlimitedAllowanceERC20Token.sol"; diff --git a/contracts/core/contracts/tokens/ERC721Token/ERC721Token.sol b/contracts/core/contracts/tokens/ERC721Token/ERC721Token.sol index 530f080c0..600cee1ab 100644 --- a/contracts/core/contracts/tokens/ERC721Token/ERC721Token.sol +++ b/contracts/core/contracts/tokens/ERC721Token/ERC721Token.sol @@ -20,7 +20,7 @@ pragma solidity 0.4.24; import "./IERC721Token.sol"; import "./IERC721Receiver.sol"; -import "../../utils/SafeMath/SafeMath.sol"; +import "@0x/contracts-utils/contracts/utils/SafeMath/SafeMath.sol"; contract ERC721Token is diff --git a/contracts/core/package.json b/contracts/core/package.json index b20b0ef3f..701e1866e 100644 --- a/contracts/core/package.json +++ b/contracts/core/package.json @@ -1,6 +1,6 @@ { "private": true, - "name": "contracts", + "name": "@0x/contracts-core", "version": "2.1.56", "engines": { "node": ">=6.12" @@ -33,20 +33,19 @@ "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" + "abis": "generated-artifacts/@(AssetProxyOwner|DummyERC20Token|DummyERC721Receiver|DummyERC721Token|DummyMultipleReturnERC20Token|DummyNoReturnERC20Token|DutchAuction|ERC20Token|ERC20Proxy|ERC721Token|ERC721Proxy|Forwarder|Exchange|ExchangeWrapper|IAssetData|IAssetProxy|InvalidERC721Receiver|MixinAuthorizable|MultiAssetProxy|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/contracts/core/README.md", "devDependencies": { + "@0x/contracts-test-utils": "^1.0.0", "@0x/abi-gen": "^1.0.17", "@0x/dev-utils": "^1.0.19", "@0x/sol-compiler": "^1.1.14", @@ -54,7 +53,6 @@ "@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", @@ -63,6 +61,7 @@ "chai-bignumber": "^2.0.1", "dirty-chai": "^2.0.1", "make-promises-safe": "^1.1.0", + "ethereumjs-abi": "0.6.5", "mocha": "^4.1.0", "npm-run-all": "^4.1.2", "shx": "^0.2.2", @@ -75,6 +74,8 @@ "dependencies": { "@0x/base-contract": "^3.0.8", "@0x/order-utils": "^3.0.4", + "@0x/contracts-multisig": "^1.0.0", + "@0x/contracts-utils": "^1.0.0", "@0x/types": "^1.3.0", "@0x/typescript-typings": "^3.0.4", "@0x/utils": "^2.0.6", @@ -82,10 +83,7 @@ "@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": { diff --git a/contracts/core/src/artifacts/index.ts b/contracts/core/src/artifacts/index.ts index 97c1b6209..b925ec87f 100644 --- a/contracts/core/src/artifacts/index.ts +++ b/contracts/core/src/artifacts/index.ts @@ -6,6 +6,7 @@ import * as DummyERC721Receiver from '../../generated-artifacts/DummyERC721Recei 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 DutchAuction from '../../generated-artifacts/DutchAuction.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'; @@ -20,15 +21,11 @@ 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'; @@ -45,6 +42,7 @@ export const artifacts = { DummyERC721Token: DummyERC721Token as ContractArtifact, DummyMultipleReturnERC20Token: DummyMultipleReturnERC20Token as ContractArtifact, DummyNoReturnERC20Token: DummyNoReturnERC20Token as ContractArtifact, + DutchAuction: DutchAuction as ContractArtifact, ERC20Proxy: ERC20Proxy as ContractArtifact, ERC20Token: ERC20Token as ContractArtifact, ERC721Proxy: ERC721Proxy as ContractArtifact, @@ -59,15 +57,11 @@ export const artifacts = { 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, diff --git a/contracts/core/src/wrappers/index.ts b/contracts/core/src/wrappers/index.ts index 9ca676b56..0a64a4db0 100644 --- a/contracts/core/src/wrappers/index.ts +++ b/contracts/core/src/wrappers/index.ts @@ -4,6 +4,7 @@ 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/dutch_auction'; export * from '../../generated-wrappers/erc20_proxy'; export * from '../../generated-wrappers/erc721_proxy'; export * from '../../generated-wrappers/erc20_token'; @@ -15,15 +16,11 @@ 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'; diff --git a/contracts/core/test/asset_proxy/authorizable.ts b/contracts/core/test/asset_proxy/authorizable.ts index e21af9b81..853d18be0 100644 --- a/contracts/core/test/asset_proxy/authorizable.ts +++ b/contracts/core/test/asset_proxy/authorizable.ts @@ -1,3 +1,11 @@ +import { + chaiSetup, + constants, + expectTransactionFailedAsync, + provider, + txDefaults, + web3Wrapper, +} from '@0x/contracts-test-utils'; import { BlockchainLifecycle } from '@0x/dev-utils'; import { RevertReason } from '@0x/types'; import { BigNumber } from '@0x/utils'; @@ -6,10 +14,6 @@ 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; diff --git a/contracts/core/test/asset_proxy/proxies.ts b/contracts/core/test/asset_proxy/proxies.ts index 8fa1e602a..2527b0fbf 100644 --- a/contracts/core/test/asset_proxy/proxies.ts +++ b/contracts/core/test/asset_proxy/proxies.ts @@ -1,3 +1,13 @@ +import { + chaiSetup, + constants, + expectTransactionFailedAsync, + expectTransactionFailedWithoutReasonAsync, + LogDecoder, + provider, + txDefaults, + web3Wrapper, +} from '@0x/contracts-test-utils'; import { BlockchainLifecycle } from '@0x/dev-utils'; import { assetDataUtils } from '@0x/order-utils'; import { RevertReason } from '@0x/types'; @@ -16,13 +26,8 @@ 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; @@ -553,7 +558,7 @@ describe('Asset Transfer Proxies', () => { erc721Receiver.address, amount, ); - const logDecoder = new LogDecoder(web3Wrapper); + const logDecoder = new LogDecoder(web3Wrapper, artifacts); const tx = await logDecoder.getTxWithDecodedLogsAsync( await web3Wrapper.sendTransactionAsync({ to: erc721Proxy.address, diff --git a/contracts/core/test/exchange/core.ts b/contracts/core/test/exchange/core.ts index 9159b0d8f..fd6b9ee6b 100644 --- a/contracts/core/test/exchange/core.ts +++ b/contracts/core/test/exchange/core.ts @@ -1,3 +1,16 @@ +import { + chaiSetup, + constants, + ERC20BalancesByOwner, + expectTransactionFailedAsync, + getLatestBlockTimestampAsync, + increaseTimeAndMineBlockAsync, + OrderFactory, + OrderStatus, + provider, + txDefaults, + web3Wrapper, +} from '@0x/contracts-test-utils'; import { BlockchainLifecycle } from '@0x/dev-utils'; import { assetDataUtils, orderHashUtils } from '@0x/order-utils'; import { RevertReason, SignatureType, SignedOrder } from '@0x/types'; @@ -19,16 +32,9 @@ import { MultiAssetProxyContract } from '../../generated-wrappers/multi_asset_pr 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; diff --git a/contracts/core/test/exchange/dispatcher.ts b/contracts/core/test/exchange/dispatcher.ts index 3d3aa42c2..9bc5cbcce 100644 --- a/contracts/core/test/exchange/dispatcher.ts +++ b/contracts/core/test/exchange/dispatcher.ts @@ -1,3 +1,12 @@ +import { + chaiSetup, + constants, + expectTransactionFailedAsync, + LogDecoder, + provider, + txDefaults, + web3Wrapper, +} from '@0x/contracts-test-utils'; import { BlockchainLifecycle } from '@0x/dev-utils'; import { assetDataUtils } from '@0x/order-utils'; import { AssetProxyId, RevertReason } from '@0x/types'; @@ -14,13 +23,8 @@ import { 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; @@ -145,7 +149,7 @@ describe('AssetProxyDispatcher', () => { }); it('should log an event with correct arguments when an asset proxy is registered', async () => { - const logDecoder = new LogDecoder(web3Wrapper); + const logDecoder = new LogDecoder(web3Wrapper, artifacts); const txReceipt = await logDecoder.getTxWithDecodedLogsAsync( await assetProxyDispatcher.registerAssetProxy.sendTransactionAsync(erc20Proxy.address, { from: owner }), ); diff --git a/contracts/core/test/exchange/fill_order.ts b/contracts/core/test/exchange/fill_order.ts index 37efaad2b..2bdbe4855 100644 --- a/contracts/core/test/exchange/fill_order.ts +++ b/contracts/core/test/exchange/fill_order.ts @@ -1,23 +1,25 @@ -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, + chaiSetup, ExpirationTimeSecondsScenario, FeeRecipientAddressScenario, FillScenario, OrderAssetAmountScenario, + provider, TakerAssetFillAmountScenario, TakerScenario, -} from '../utils/types'; -import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper'; + txDefaults, + web3Wrapper, +} from '@0x/contracts-test-utils'; +import { BlockchainLifecycle } from '@0x/dev-utils'; +import * as _ from 'lodash'; + +import { + FillOrderCombinatorialUtils, + fillOrderCombinatorialUtilsFactoryAsync, +} from '../utils/fill_order_combinatorial_utils'; chaiSetup.configure(); const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); diff --git a/contracts/core/test/exchange/internal.ts b/contracts/core/test/exchange/internal.ts index 109be29c6..972f5efb6 100644 --- a/contracts/core/test/exchange/internal.ts +++ b/contracts/core/test/exchange/internal.ts @@ -1,3 +1,15 @@ +import { + bytes32Values, + chaiSetup, + constants, + FillResults, + getRevertReasonOrErrorMessageForSendTransactionAsync, + provider, + testCombinatoriallyWithReferenceFuncAsync, + txDefaults, + uint256Values, + web3Wrapper, +} from '@0x/contracts-test-utils'; import { BlockchainLifecycle } from '@0x/dev-utils'; import { Order, RevertReason, SignedOrder } from '@0x/types'; import { BigNumber } from '@0x/utils'; @@ -6,12 +18,6 @@ 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; diff --git a/contracts/core/test/exchange/libs.ts b/contracts/core/test/exchange/libs.ts index 503ef0e0f..44ff6a844 100644 --- a/contracts/core/test/exchange/libs.ts +++ b/contracts/core/test/exchange/libs.ts @@ -1,17 +1,20 @@ +import { + addressUtils, + chaiSetup, + constants, + OrderFactory, + provider, + txDefaults, + web3Wrapper, +} from '@0x/contracts-test-utils'; 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; @@ -22,7 +25,6 @@ describe('Exchange libs', () => { let signedOrder: SignedOrder; let orderFactory: OrderFactory; let libs: TestLibsContract; - let testConstants: TestConstantsContract; before(async () => { await blockchainLifecycle.startAsync(); @@ -34,11 +36,6 @@ describe('Exchange libs', () => { 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, @@ -58,15 +55,6 @@ describe('Exchange libs', () => { 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. diff --git a/contracts/core/test/exchange/match_orders.ts b/contracts/core/test/exchange/match_orders.ts index eea9992d9..0e841b359 100644 --- a/contracts/core/test/exchange/match_orders.ts +++ b/contracts/core/test/exchange/match_orders.ts @@ -1,3 +1,14 @@ +import { + chaiSetup, + constants, + ERC20BalancesByOwner, + ERC721TokenIdsByOwner, + expectTransactionFailedAsync, + OrderFactory, + provider, + txDefaults, + web3Wrapper, +} from '@0x/contracts-test-utils'; import { BlockchainLifecycle } from '@0x/dev-utils'; import { assetDataUtils } from '@0x/order-utils'; import { RevertReason } from '@0x/types'; @@ -14,16 +25,10 @@ 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(); diff --git a/contracts/core/test/exchange/signature_validator.ts b/contracts/core/test/exchange/signature_validator.ts index 756c72766..b84a488a1 100644 --- a/contracts/core/test/exchange/signature_validator.ts +++ b/contracts/core/test/exchange/signature_validator.ts @@ -1,3 +1,14 @@ +import { + addressUtils, + chaiSetup, + constants, + expectContractCallFailedAsync, + LogDecoder, + OrderFactory, + provider, + txDefaults, + web3Wrapper, +} from '@0x/contracts-test-utils'; import { BlockchainLifecycle } from '@0x/dev-utils'; import { assetDataUtils, orderHashUtils, signatureUtils } from '@0x/order-utils'; import { RevertReason, SignatureType, SignedOrder } from '@0x/types'; @@ -13,13 +24,6 @@ import { TestStaticCallReceiverContract } from '../../generated-wrappers/test_st 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; @@ -73,7 +77,7 @@ describe('MixinSignatureValidator', () => { provider, txDefaults, ); - signatureValidatorLogDecoder = new LogDecoder(web3Wrapper); + signatureValidatorLogDecoder = new LogDecoder(web3Wrapper, artifacts); await web3Wrapper.awaitTransactionSuccessAsync( await signatureValidator.setSignatureValidatorApproval.sendTransactionAsync(testValidator.address, true, { from: signerAddress, diff --git a/contracts/core/test/exchange/transactions.ts b/contracts/core/test/exchange/transactions.ts index 1b5eef295..c4086d9be 100644 --- a/contracts/core/test/exchange/transactions.ts +++ b/contracts/core/test/exchange/transactions.ts @@ -1,3 +1,16 @@ +import { + chaiSetup, + constants, + ERC20BalancesByOwner, + expectTransactionFailedAsync, + OrderFactory, + orderUtils, + provider, + SignedTransaction, + TransactionFactory, + txDefaults, + web3Wrapper, +} from '@0x/contracts-test-utils'; import { BlockchainLifecycle } from '@0x/dev-utils'; import { assetDataUtils, generatePseudoRandomSalt } from '@0x/order-utils'; import { OrderWithoutExchangeAddress, RevertReason, SignedOrder } from '@0x/types'; @@ -11,16 +24,8 @@ 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; diff --git a/contracts/core/test/exchange/wrapper.ts b/contracts/core/test/exchange/wrapper.ts index 6b660aac5..17cb7a3bb 100644 --- a/contracts/core/test/exchange/wrapper.ts +++ b/contracts/core/test/exchange/wrapper.ts @@ -1,3 +1,16 @@ +import { + chaiSetup, + constants, + ERC20BalancesByOwner, + expectTransactionFailedAsync, + getLatestBlockTimestampAsync, + increaseTimeAndMineBlockAsync, + OrderFactory, + OrderStatus, + provider, + txDefaults, + web3Wrapper, +} from '@0x/contracts-test-utils'; import { BlockchainLifecycle } from '@0x/dev-utils'; import { assetDataUtils, orderHashUtils } from '@0x/order-utils'; import { RevertReason, SignedOrder } from '@0x/types'; @@ -13,16 +26,9 @@ 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; diff --git a/contracts/core/test/extensions/dutch_auction.ts b/contracts/core/test/extensions/dutch_auction.ts new file mode 100644 index 000000000..6bed222f4 --- /dev/null +++ b/contracts/core/test/extensions/dutch_auction.ts @@ -0,0 +1,491 @@ +import { + chaiSetup, + constants, + ContractName, + ERC20BalancesByOwner, + expectTransactionFailedAsync, + getLatestBlockTimestampAsync, + OrderFactory, + provider, + txDefaults, + web3Wrapper, +} from '@0x/contracts-test-utils'; +import { BlockchainLifecycle } from '@0x/dev-utils'; +import { assetDataUtils, generatePseudoRandomSalt } from '@0x/order-utils'; +import { RevertReason, SignedOrder } from '@0x/types'; +import { BigNumber } from '@0x/utils'; +import { Web3Wrapper } from '@0x/web3-wrapper'; +import * as chai from 'chai'; +import ethAbi = require('ethereumjs-abi'); +import * as ethUtil from 'ethereumjs-util'; +import * as _ from 'lodash'; + +import { DummyERC20TokenContract } from '../../generated-wrappers/dummy_erc20_token'; +import { DummyERC721TokenContract } from '../../generated-wrappers/dummy_erc721_token'; +import { DutchAuctionContract } from '../../generated-wrappers/dutch_auction'; +import { ExchangeContract } from '../../generated-wrappers/exchange'; +import { WETH9Contract } from '../../generated-wrappers/weth9'; +import { artifacts } from '../../src/artifacts'; +import { ERC20Wrapper } from '../utils/erc20_wrapper'; +import { ERC721Wrapper } from '../utils/erc721_wrapper'; +import { ExchangeWrapper } from '../utils/exchange_wrapper'; + +chaiSetup.configure(); +const expect = chai.expect; +const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); +const DECIMALS_DEFAULT = 18; + +describe(ContractName.DutchAuction, () => { + let makerAddress: string; + let owner: string; + let takerAddress: string; + let feeRecipientAddress: string; + let defaultMakerAssetAddress: string; + + let zrxToken: DummyERC20TokenContract; + let erc20TokenA: DummyERC20TokenContract; + let erc721Token: DummyERC721TokenContract; + let dutchAuctionContract: DutchAuctionContract; + let wethContract: WETH9Contract; + + let sellerOrderFactory: OrderFactory; + let buyerOrderFactory: OrderFactory; + let erc20Wrapper: ERC20Wrapper; + let erc20Balances: ERC20BalancesByOwner; + let currentBlockTimestamp: number; + let auctionBeginTimeSeconds: BigNumber; + let auctionEndTimeSeconds: BigNumber; + let auctionBeginAmount: BigNumber; + let auctionEndAmount: BigNumber; + let sellOrder: SignedOrder; + let buyOrder: SignedOrder; + let erc721MakerAssetIds: BigNumber[]; + const tenMinutesInSeconds = 10 * 60; + + async function increaseTimeAsync(): Promise<void> { + const timestampBefore = await getLatestBlockTimestampAsync(); + await web3Wrapper.increaseTimeAsync(5); + const timestampAfter = await getLatestBlockTimestampAsync(); + // HACK send some transactions when a time increase isn't supported + if (timestampAfter === timestampBefore) { + await web3Wrapper.sendTransactionAsync({ to: makerAddress, from: makerAddress, value: new BigNumber(1) }); + } + } + + function extendMakerAssetData(makerAssetData: string, beginTimeSeconds: BigNumber, beginAmount: BigNumber): string { + return ethUtil.bufferToHex( + Buffer.concat([ + ethUtil.toBuffer(makerAssetData), + ethUtil.toBuffer( + (ethAbi as any).rawEncode( + ['uint256', 'uint256'], + [beginTimeSeconds.toString(), beginAmount.toString()], + ), + ), + ]), + ); + } + + before(async () => { + await blockchainLifecycle.startAsync(); + const accounts = await web3Wrapper.getAvailableAddressesAsync(); + const usedAddresses = ([owner, makerAddress, takerAddress, feeRecipientAddress] = accounts); + + erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner); + + const numDummyErc20ToDeploy = 2; + [erc20TokenA, zrxToken] = await erc20Wrapper.deployDummyTokensAsync( + numDummyErc20ToDeploy, + constants.DUMMY_TOKEN_DECIMALS, + ); + const erc20Proxy = await erc20Wrapper.deployProxyAsync(); + await erc20Wrapper.setBalancesAndAllowancesAsync(); + + const erc721Wrapper = new ERC721Wrapper(provider, usedAddresses, owner); + [erc721Token] = await erc721Wrapper.deployDummyTokensAsync(); + const erc721Proxy = await erc721Wrapper.deployProxyAsync(); + await erc721Wrapper.setBalancesAndAllowancesAsync(); + const erc721Balances = await erc721Wrapper.getBalancesAsync(); + erc721MakerAssetIds = erc721Balances[makerAddress][erc721Token.address]; + + wethContract = await WETH9Contract.deployFrom0xArtifactAsync(artifacts.WETH9, provider, txDefaults); + erc20Wrapper.addDummyTokenContract(wethContract as any); + + const zrxAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address); + const exchangeInstance = await ExchangeContract.deployFrom0xArtifactAsync( + artifacts.Exchange, + provider, + txDefaults, + zrxAssetData, + ); + const exchangeWrapper = new ExchangeWrapper(exchangeInstance, provider); + await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner); + await exchangeWrapper.registerAssetProxyAsync(erc721Proxy.address, owner); + + await erc20Proxy.addAuthorizedAddress.sendTransactionAsync(exchangeInstance.address, { + from: owner, + }); + await erc721Proxy.addAuthorizedAddress.sendTransactionAsync(exchangeInstance.address, { + from: owner, + }); + + const dutchAuctionInstance = await DutchAuctionContract.deployFrom0xArtifactAsync( + artifacts.DutchAuction, + provider, + txDefaults, + exchangeInstance.address, + ); + dutchAuctionContract = new DutchAuctionContract( + dutchAuctionInstance.abi, + dutchAuctionInstance.address, + provider, + ); + + defaultMakerAssetAddress = erc20TokenA.address; + const defaultTakerAssetAddress = wethContract.address; + + // Set up taker WETH balance and allowance + await web3Wrapper.awaitTransactionSuccessAsync( + await wethContract.deposit.sendTransactionAsync({ + from: takerAddress, + value: Web3Wrapper.toBaseUnitAmount(new BigNumber(50), DECIMALS_DEFAULT), + }), + ); + await web3Wrapper.awaitTransactionSuccessAsync( + await wethContract.approve.sendTransactionAsync( + erc20Proxy.address, + constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS, + { from: takerAddress }, + ), + ); + web3Wrapper.abiDecoder.addABI(exchangeInstance.abi); + web3Wrapper.abiDecoder.addABI(zrxToken.abi); + erc20Wrapper.addTokenOwnerAddress(dutchAuctionContract.address); + + currentBlockTimestamp = await getLatestBlockTimestampAsync(); + // Default auction begins 10 minutes ago + auctionBeginTimeSeconds = new BigNumber(currentBlockTimestamp).minus(tenMinutesInSeconds); + // Default auction ends 10 from now + auctionEndTimeSeconds = new BigNumber(currentBlockTimestamp).plus(tenMinutesInSeconds); + auctionBeginAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(10), DECIMALS_DEFAULT); + auctionEndAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(1), DECIMALS_DEFAULT); + + // Default sell order and buy order are exact mirrors + const sellerDefaultOrderParams = { + salt: generatePseudoRandomSalt(), + exchangeAddress: exchangeInstance.address, + makerAddress, + feeRecipientAddress, + // taker address or sender address should be set to the ducth auction contract + takerAddress: dutchAuctionContract.address, + makerAssetData: extendMakerAssetData( + assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress), + auctionBeginTimeSeconds, + auctionBeginAmount, + ), + takerAssetData: assetDataUtils.encodeERC20AssetData(defaultTakerAssetAddress), + makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(200), DECIMALS_DEFAULT), + takerAssetAmount: auctionEndAmount, + expirationTimeSeconds: auctionEndTimeSeconds, + makerFee: constants.ZERO_AMOUNT, + takerFee: constants.ZERO_AMOUNT, + }; + // Default buy order is for the auction begin price + const buyerDefaultOrderParams = { + ...sellerDefaultOrderParams, + makerAddress: takerAddress, + makerAssetData: sellerDefaultOrderParams.takerAssetData, + takerAssetData: sellerDefaultOrderParams.makerAssetData, + makerAssetAmount: auctionBeginAmount, + takerAssetAmount: sellerDefaultOrderParams.makerAssetAmount, + }; + const makerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddress)]; + const takerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(takerAddress)]; + sellerOrderFactory = new OrderFactory(makerPrivateKey, sellerDefaultOrderParams); + buyerOrderFactory = new OrderFactory(takerPrivateKey, buyerDefaultOrderParams); + }); + after(async () => { + await blockchainLifecycle.revertAsync(); + }); + beforeEach(async () => { + await blockchainLifecycle.startAsync(); + erc20Balances = await erc20Wrapper.getBalancesAsync(); + sellOrder = await sellerOrderFactory.newSignedOrderAsync(); + buyOrder = await buyerOrderFactory.newSignedOrderAsync(); + }); + afterEach(async () => { + await blockchainLifecycle.revertAsync(); + }); + describe('matchOrders', () => { + it('should be worth the begin price at the begining of the auction', async () => { + auctionBeginTimeSeconds = new BigNumber(currentBlockTimestamp + 2); + sellOrder = await sellerOrderFactory.newSignedOrderAsync({ + makerAssetData: extendMakerAssetData( + assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress), + auctionBeginTimeSeconds, + auctionBeginAmount, + ), + }); + const auctionDetails = await dutchAuctionContract.getAuctionDetails.callAsync(sellOrder); + expect(auctionDetails.currentAmount).to.be.bignumber.equal(auctionBeginAmount); + expect(auctionDetails.beginAmount).to.be.bignumber.equal(auctionBeginAmount); + }); + it('should be be worth the end price at the end of the auction', async () => { + auctionBeginTimeSeconds = new BigNumber(currentBlockTimestamp - tenMinutesInSeconds * 2); + auctionEndTimeSeconds = new BigNumber(currentBlockTimestamp - tenMinutesInSeconds); + sellOrder = await sellerOrderFactory.newSignedOrderAsync({ + makerAssetData: extendMakerAssetData( + assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress), + auctionBeginTimeSeconds, + auctionBeginAmount, + ), + expirationTimeSeconds: auctionEndTimeSeconds, + }); + const auctionDetails = await dutchAuctionContract.getAuctionDetails.callAsync(sellOrder); + expect(auctionDetails.currentAmount).to.be.bignumber.equal(auctionEndAmount); + expect(auctionDetails.beginAmount).to.be.bignumber.equal(auctionBeginAmount); + }); + it('should match orders at current amount and send excess to buyer', async () => { + const beforeAuctionDetails = await dutchAuctionContract.getAuctionDetails.callAsync(sellOrder); + buyOrder = await buyerOrderFactory.newSignedOrderAsync({ + makerAssetAmount: beforeAuctionDetails.currentAmount.times(2), + }); + await web3Wrapper.awaitTransactionSuccessAsync( + await dutchAuctionContract.matchOrders.sendTransactionAsync( + buyOrder, + sellOrder, + buyOrder.signature, + sellOrder.signature, + { + from: takerAddress, + }, + ), + ); + const afterAuctionDetails = await dutchAuctionContract.getAuctionDetails.callAsync(sellOrder); + const newBalances = await erc20Wrapper.getBalancesAsync(); + expect(newBalances[dutchAuctionContract.address][wethContract.address]).to.be.bignumber.equal( + constants.ZERO_AMOUNT, + ); + // HACK gte used here due to a bug in ganache where the timestamp can change + // between multiple calls to the same block. Which can move the amount in our case + // ref: https://github.com/trufflesuite/ganache-core/issues/111 + expect(newBalances[makerAddress][wethContract.address]).to.be.bignumber.gte( + erc20Balances[makerAddress][wethContract.address].plus(afterAuctionDetails.currentAmount), + ); + expect(newBalances[takerAddress][wethContract.address]).to.be.bignumber.gte( + erc20Balances[takerAddress][wethContract.address].minus(beforeAuctionDetails.currentAmount), + ); + }); + it('should have valid getAuctionDetails at some block in the future', async () => { + let auctionDetails = await dutchAuctionContract.getAuctionDetails.callAsync(sellOrder); + const beforeAmount = auctionDetails.currentAmount; + await increaseTimeAsync(); + auctionDetails = await dutchAuctionContract.getAuctionDetails.callAsync(sellOrder); + const currentAmount = auctionDetails.currentAmount; + expect(beforeAmount).to.be.bignumber.greaterThan(currentAmount); + + buyOrder = await buyerOrderFactory.newSignedOrderAsync({ + makerAssetAmount: currentAmount, + }); + const txHash = await dutchAuctionContract.matchOrders.sendTransactionAsync( + buyOrder, + sellOrder, + buyOrder.signature, + sellOrder.signature, + { + from: takerAddress, + // HACK geth seems to miscalculate the gas required intermittently + gas: 400000, + }, + ); + await web3Wrapper.awaitTransactionSuccessAsync(txHash); + const newBalances = await erc20Wrapper.getBalancesAsync(); + expect(newBalances[makerAddress][wethContract.address]).to.be.bignumber.equal( + erc20Balances[makerAddress][wethContract.address].plus(currentAmount), + ); + }); + it('maker fees on sellOrder are paid to the fee receipient', async () => { + sellOrder = await sellerOrderFactory.newSignedOrderAsync({ + makerFee: new BigNumber(1), + }); + const txHash = await dutchAuctionContract.matchOrders.sendTransactionAsync( + buyOrder, + sellOrder, + buyOrder.signature, + sellOrder.signature, + { + from: takerAddress, + }, + ); + await web3Wrapper.awaitTransactionSuccessAsync(txHash); + const afterAuctionDetails = await dutchAuctionContract.getAuctionDetails.callAsync(sellOrder); + const newBalances = await erc20Wrapper.getBalancesAsync(); + expect(newBalances[makerAddress][wethContract.address]).to.be.bignumber.gte( + erc20Balances[makerAddress][wethContract.address].plus(afterAuctionDetails.currentAmount), + ); + expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal( + erc20Balances[feeRecipientAddress][zrxToken.address].plus(sellOrder.makerFee), + ); + }); + it('maker fees on buyOrder are paid to the fee receipient', async () => { + buyOrder = await buyerOrderFactory.newSignedOrderAsync({ + makerFee: new BigNumber(1), + }); + const txHash = await dutchAuctionContract.matchOrders.sendTransactionAsync( + buyOrder, + sellOrder, + buyOrder.signature, + sellOrder.signature, + { + from: takerAddress, + }, + ); + await web3Wrapper.awaitTransactionSuccessAsync(txHash); + const newBalances = await erc20Wrapper.getBalancesAsync(); + const afterAuctionDetails = await dutchAuctionContract.getAuctionDetails.callAsync(sellOrder); + expect(newBalances[makerAddress][wethContract.address]).to.be.bignumber.gte( + erc20Balances[makerAddress][wethContract.address].plus(afterAuctionDetails.currentAmount), + ); + expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal( + erc20Balances[feeRecipientAddress][zrxToken.address].plus(buyOrder.makerFee), + ); + }); + it('should revert when auction expires', async () => { + auctionBeginTimeSeconds = new BigNumber(currentBlockTimestamp - tenMinutesInSeconds * 2); + auctionEndTimeSeconds = new BigNumber(currentBlockTimestamp - tenMinutesInSeconds); + sellOrder = await sellerOrderFactory.newSignedOrderAsync({ + expirationTimeSeconds: auctionEndTimeSeconds, + makerAssetData: extendMakerAssetData( + assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress), + auctionBeginTimeSeconds, + auctionBeginAmount, + ), + }); + return expectTransactionFailedAsync( + dutchAuctionContract.matchOrders.sendTransactionAsync( + buyOrder, + sellOrder, + buyOrder.signature, + sellOrder.signature, + { + from: takerAddress, + }, + ), + RevertReason.AuctionExpired, + ); + }); + it('cannot be filled for less than the current price', async () => { + await increaseTimeAsync(); + buyOrder = await buyerOrderFactory.newSignedOrderAsync({ + makerAssetAmount: sellOrder.takerAssetAmount, + }); + return expectTransactionFailedAsync( + dutchAuctionContract.matchOrders.sendTransactionAsync( + buyOrder, + sellOrder, + buyOrder.signature, + sellOrder.signature, + { + from: takerAddress, + }, + ), + RevertReason.AuctionInvalidAmount, + ); + }); + it('auction begin amount must be higher than final amount ', async () => { + sellOrder = await sellerOrderFactory.newSignedOrderAsync({ + takerAssetAmount: auctionBeginAmount.plus(1), + }); + return expectTransactionFailedAsync( + dutchAuctionContract.matchOrders.sendTransactionAsync( + buyOrder, + sellOrder, + buyOrder.signature, + sellOrder.signature, + { + from: takerAddress, + }, + ), + RevertReason.AuctionInvalidAmount, + ); + }); + it('begin time is less than end time', async () => { + auctionBeginTimeSeconds = new BigNumber(auctionEndTimeSeconds).plus(tenMinutesInSeconds); + sellOrder = await sellerOrderFactory.newSignedOrderAsync({ + expirationTimeSeconds: auctionEndTimeSeconds, + makerAssetData: extendMakerAssetData( + assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress), + auctionBeginTimeSeconds, + auctionBeginAmount, + ), + }); + return expectTransactionFailedAsync( + dutchAuctionContract.matchOrders.sendTransactionAsync( + buyOrder, + sellOrder, + buyOrder.signature, + sellOrder.signature, + { + from: takerAddress, + }, + ), + RevertReason.AuctionInvalidBeginTime, + ); + }); + it('asset data contains auction parameters', async () => { + sellOrder = await sellerOrderFactory.newSignedOrderAsync({ + makerAssetData: assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress), + }); + return expectTransactionFailedAsync( + dutchAuctionContract.matchOrders.sendTransactionAsync( + buyOrder, + sellOrder, + buyOrder.signature, + sellOrder.signature, + { + from: takerAddress, + }, + ), + RevertReason.InvalidAssetData, + ); + }); + describe('ERC721', () => { + it('should match orders when ERC721', async () => { + const makerAssetId = erc721MakerAssetIds[0]; + sellOrder = await sellerOrderFactory.newSignedOrderAsync({ + makerAssetAmount: new BigNumber(1), + makerAssetData: extendMakerAssetData( + assetDataUtils.encodeERC721AssetData(erc721Token.address, makerAssetId), + auctionBeginTimeSeconds, + auctionBeginAmount, + ), + }); + buyOrder = await buyerOrderFactory.newSignedOrderAsync({ + takerAssetAmount: new BigNumber(1), + takerAssetData: sellOrder.makerAssetData, + }); + await web3Wrapper.awaitTransactionSuccessAsync( + await dutchAuctionContract.matchOrders.sendTransactionAsync( + buyOrder, + sellOrder, + buyOrder.signature, + sellOrder.signature, + { + from: takerAddress, + }, + ), + ); + const afterAuctionDetails = await dutchAuctionContract.getAuctionDetails.callAsync(sellOrder); + const newBalances = await erc20Wrapper.getBalancesAsync(); + // HACK gte used here due to a bug in ganache where the timestamp can change + // between multiple calls to the same block. Which can move the amount in our case + // ref: https://github.com/trufflesuite/ganache-core/issues/111 + expect(newBalances[makerAddress][wethContract.address]).to.be.bignumber.gte( + erc20Balances[makerAddress][wethContract.address].plus(afterAuctionDetails.currentAmount), + ); + const newOwner = await erc721Token.ownerOf.callAsync(makerAssetId); + expect(newOwner).to.be.bignumber.equal(takerAddress); + }); + }); + }); +}); diff --git a/contracts/core/test/extensions/forwarder.ts b/contracts/core/test/extensions/forwarder.ts index c006be0fe..44ad4d6ff 100644 --- a/contracts/core/test/extensions/forwarder.ts +++ b/contracts/core/test/extensions/forwarder.ts @@ -1,3 +1,16 @@ +import { + chaiSetup, + constants, + ContractName, + ERC20BalancesByOwner, + expectContractCreationFailedAsync, + expectTransactionFailedAsync, + OrderFactory, + provider, + sendTransactionResult, + txDefaults, + web3Wrapper, +} from '@0x/contracts-test-utils'; import { BlockchainLifecycle } from '@0x/dev-utils'; import { assetDataUtils } from '@0x/order-utils'; import { RevertReason, SignedOrder } from '@0x/types'; @@ -12,20 +25,10 @@ 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; diff --git a/contracts/core/test/extensions/order_validator.ts b/contracts/core/test/extensions/order_validator.ts index 37d7c4c5a..3dbe76f6e 100644 --- a/contracts/core/test/extensions/order_validator.ts +++ b/contracts/core/test/extensions/order_validator.ts @@ -1,3 +1,12 @@ +import { + chaiSetup, + constants, + OrderFactory, + OrderStatus, + provider, + txDefaults, + web3Wrapper, +} from '@0x/contracts-test-utils'; import { BlockchainLifecycle } from '@0x/dev-utils'; import { assetDataUtils, orderHashUtils } from '@0x/order-utils'; import { SignedOrder } from '@0x/types'; @@ -12,14 +21,9 @@ 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; diff --git a/contracts/core/test/global_hooks.ts b/contracts/core/test/global_hooks.ts index 2e9ac9e21..f8ace376a 100644 --- a/contracts/core/test/global_hooks.ts +++ b/contracts/core/test/global_hooks.ts @@ -1,8 +1,9 @@ import { env, EnvVars } from '@0x/dev-utils'; -import { coverage } from './utils/coverage'; -import { profiler } from './utils/profiler'; - +import { coverage, profiler, provider } from '@0x/contracts-test-utils'; +before('start web3 provider', () => { + provider.start(); +}); after('generate coverage report', async () => { if (env.parseBoolean(EnvVars.SolidityCoverage)) { const coverageSubprovider = coverage.getCoverageSubproviderSingleton(); @@ -12,4 +13,5 @@ after('generate coverage report', async () => { const profilerSubprovider = profiler.getProfilerSubproviderSingleton(); await profilerSubprovider.writeProfilerOutputAsync(); } + provider.stop(); }); diff --git a/contracts/core/test/multisig/asset_proxy_owner.ts b/contracts/core/test/multisig/asset_proxy_owner.ts index 087152316..daebfb7fb 100644 --- a/contracts/core/test/multisig/asset_proxy_owner.ts +++ b/contracts/core/test/multisig/asset_proxy_owner.ts @@ -1,3 +1,16 @@ +import { + chaiSetup, + constants, + expectContractCallFailedAsync, + expectContractCreationFailedAsync, + expectTransactionFailedAsync, + expectTransactionFailedWithoutReasonAsync, + increaseTimeAndMineBlockAsync, + provider, + sendTransactionResult, + txDefaults, + web3Wrapper, +} from '@0x/contracts-test-utils'; import { BlockchainLifecycle } from '@0x/dev-utils'; import { RevertReason } from '@0x/types'; import { BigNumber } from '@0x/utils'; @@ -14,18 +27,7 @@ import { 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'; +import { AssetProxyOwnerWrapper } from '../utils/asset_proxy_owner_wrapper'; chaiSetup.configure(); const expect = chai.expect; @@ -41,7 +43,7 @@ describe('AssetProxyOwner', () => { let erc20Proxy: MixinAuthorizableContract; let erc721Proxy: MixinAuthorizableContract; let testAssetProxyOwner: TestAssetProxyOwnerContract; - let multiSigWrapper: MultiSigWrapper; + let assetProxyOwnerWrapper: AssetProxyOwnerWrapper; before(async () => { await blockchainLifecycle.startAsync(); @@ -75,7 +77,7 @@ describe('AssetProxyOwner', () => { REQUIRED_APPROVALS, SECONDS_TIME_LOCKED, ); - multiSigWrapper = new MultiSigWrapper(testAssetProxyOwner, provider); + assetProxyOwnerWrapper = new AssetProxyOwnerWrapper(testAssetProxyOwner, provider); await web3Wrapper.awaitTransactionSuccessAsync( await erc20Proxy.transferOwnership.sendTransactionAsync(testAssetProxyOwner.address, { from: initialOwner, @@ -172,7 +174,7 @@ describe('AssetProxyOwner', () => { addressToRegister, isRegistered, ); - const submitTxRes = await multiSigWrapper.submitTransactionAsync( + const submitTxRes = await assetProxyOwnerWrapper.submitTransactionAsync( testAssetProxyOwner.address, registerAssetProxyData, owners[0], @@ -181,10 +183,10 @@ describe('AssetProxyOwner', () => { const log = submitTxRes.logs[0] as LogWithDecodedArgs<AssetProxyOwnerSubmissionEventArgs>; const txId = log.args.transactionId; - await multiSigWrapper.confirmTransactionAsync(txId, owners[1]); + await assetProxyOwnerWrapper.confirmTransactionAsync(txId, owners[1]); await increaseTimeAndMineBlockAsync(SECONDS_TIME_LOCKED.toNumber()); - const executeTxRes = await multiSigWrapper.executeTransactionAsync(txId, owners[0]); + const executeTxRes = await assetProxyOwnerWrapper.executeTransactionAsync(txId, owners[0]); const registerLog = executeTxRes.logs[0] as LogWithDecodedArgs< AssetProxyOwnerAssetProxyRegistrationEventArgs >; @@ -204,7 +206,7 @@ describe('AssetProxyOwner', () => { addressToRegister, isRegistered, ); - const submitTxRes = await multiSigWrapper.submitTransactionAsync( + const submitTxRes = await assetProxyOwnerWrapper.submitTransactionAsync( testAssetProxyOwner.address, registerAssetProxyData, owners[0], @@ -212,10 +214,10 @@ describe('AssetProxyOwner', () => { const log = submitTxRes.logs[0] as LogWithDecodedArgs<AssetProxyOwnerSubmissionEventArgs>; const txId = log.args.transactionId; - await multiSigWrapper.confirmTransactionAsync(txId, owners[1]); + await assetProxyOwnerWrapper.confirmTransactionAsync(txId, owners[1]); await increaseTimeAndMineBlockAsync(SECONDS_TIME_LOCKED.toNumber()); - const executeTxRes = await multiSigWrapper.executeTransactionAsync(txId, owners[0]); + const executeTxRes = await assetProxyOwnerWrapper.executeTransactionAsync(txId, owners[0]); const failureLog = executeTxRes.logs[0] as LogWithDecodedArgs<AssetProxyOwnerExecutionFailureEventArgs>; expect(failureLog.args.transactionId).to.be.bignumber.equal(txId); @@ -237,7 +239,7 @@ describe('AssetProxyOwner', () => { addressToRegister, isRegistered, ); - const registerAssetProxySubmitRes = await multiSigWrapper.submitTransactionAsync( + const registerAssetProxySubmitRes = await assetProxyOwnerWrapper.submitTransactionAsync( testAssetProxyOwner.address, registerAssetProxyData, owners[0], @@ -247,12 +249,12 @@ describe('AssetProxyOwner', () => { >; const addAuthorizedAddressData = erc20Proxy.addAuthorizedAddress.getABIEncodedTransactionData(authorized); - const erc20AddAuthorizedAddressSubmitRes = await multiSigWrapper.submitTransactionAsync( + const erc20AddAuthorizedAddressSubmitRes = await assetProxyOwnerWrapper.submitTransactionAsync( erc20Proxy.address, addAuthorizedAddressData, owners[0], ); - const erc721AddAuthorizedAddressSubmitRes = await multiSigWrapper.submitTransactionAsync( + const erc721AddAuthorizedAddressSubmitRes = await assetProxyOwnerWrapper.submitTransactionAsync( erc721Proxy.address, addAuthorizedAddressData, owners[0], @@ -267,15 +269,15 @@ describe('AssetProxyOwner', () => { 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 assetProxyOwnerWrapper.confirmTransactionAsync(registerAssetProxyTxId, owners[1]); + await assetProxyOwnerWrapper.confirmTransactionAsync(erc20AddAuthorizedAddressTxId, owners[1]); + await assetProxyOwnerWrapper.confirmTransactionAsync(erc721AddAuthorizedAddressTxId, owners[1]); await increaseTimeAndMineBlockAsync(SECONDS_TIME_LOCKED.toNumber()); - await multiSigWrapper.executeTransactionAsync(registerAssetProxyTxId, owners[0]); - await multiSigWrapper.executeTransactionAsync(erc20AddAuthorizedAddressTxId, owners[0], { + await assetProxyOwnerWrapper.executeTransactionAsync(registerAssetProxyTxId, owners[0]); + await assetProxyOwnerWrapper.executeTransactionAsync(erc20AddAuthorizedAddressTxId, owners[0], { gas: constants.MAX_EXECUTE_TRANSACTION_GAS, }); - await multiSigWrapper.executeTransactionAsync(erc721AddAuthorizedAddressTxId, owners[0], { + await assetProxyOwnerWrapper.executeTransactionAsync(erc721AddAuthorizedAddressTxId, owners[0], { gas: constants.MAX_EXECUTE_TRANSACTION_GAS, }); }); @@ -285,7 +287,7 @@ describe('AssetProxyOwner', () => { const notRemoveAuthorizedAddressData = erc20Proxy.addAuthorizedAddress.getABIEncodedTransactionData( authorized, ); - const submitTxRes = await multiSigWrapper.submitTransactionAsync( + const submitTxRes = await assetProxyOwnerWrapper.submitTransactionAsync( erc20Proxy.address, notRemoveAuthorizedAddressData, owners[0], @@ -303,7 +305,7 @@ describe('AssetProxyOwner', () => { authorized, erc20Index, ); - const submitTxRes = await multiSigWrapper.submitTransactionAsync( + const submitTxRes = await assetProxyOwnerWrapper.submitTransactionAsync( erc20Proxy.address, removeAuthorizedAddressAtIndexData, owners[0], @@ -321,7 +323,7 @@ describe('AssetProxyOwner', () => { authorized, erc721Index, ); - const submitTxRes = await multiSigWrapper.submitTransactionAsync( + const submitTxRes = await assetProxyOwnerWrapper.submitTransactionAsync( erc721Proxy.address, removeAuthorizedAddressAtIndexData, owners[0], @@ -341,7 +343,7 @@ describe('AssetProxyOwner', () => { authorized, erc20Index, ); - const res = await multiSigWrapper.submitTransactionAsync( + const res = await assetProxyOwnerWrapper.submitTransactionAsync( erc20Proxy.address, removeAuthorizedAddressAtIndexData, owners[0], @@ -362,7 +364,7 @@ describe('AssetProxyOwner', () => { authorized, erc721Index, ); - const res = await multiSigWrapper.submitTransactionAsync( + const res = await assetProxyOwnerWrapper.submitTransactionAsync( erc721Proxy.address, removeAuthorizedAddressAtIndexData, owners[0], @@ -370,7 +372,7 @@ describe('AssetProxyOwner', () => { const log = res.logs[0] as LogWithDecodedArgs<AssetProxyOwnerSubmissionEventArgs>; const txId = log.args.transactionId; - await multiSigWrapper.confirmTransactionAsync(txId, owners[1]); + await assetProxyOwnerWrapper.confirmTransactionAsync(txId, owners[1]); return expectTransactionFailedAsync( testAssetProxyOwner.executeRemoveAuthorizedAddressAtIndex.sendTransactionAsync(txId, { @@ -385,7 +387,7 @@ describe('AssetProxyOwner', () => { const addAuthorizedAddressData = erc20Proxy.addAuthorizedAddress.getABIEncodedTransactionData( newAuthorized, ); - const res = await multiSigWrapper.submitTransactionAsync( + const res = await assetProxyOwnerWrapper.submitTransactionAsync( erc20Proxy.address, addAuthorizedAddressData, owners[0], @@ -393,7 +395,7 @@ describe('AssetProxyOwner', () => { const log = res.logs[0] as LogWithDecodedArgs<AssetProxyOwnerSubmissionEventArgs>; const txId = log.args.transactionId; - await multiSigWrapper.confirmTransactionAsync(txId, owners[1]); + await assetProxyOwnerWrapper.confirmTransactionAsync(txId, owners[1]); return expectTransactionFailedAsync( testAssetProxyOwner.executeRemoveAuthorizedAddressAtIndex.sendTransactionAsync(txId, { @@ -411,7 +413,7 @@ describe('AssetProxyOwner', () => { authorized, erc20Index, ); - const submitRes = await multiSigWrapper.submitTransactionAsync( + const submitRes = await assetProxyOwnerWrapper.submitTransactionAsync( erc20Proxy.address, removeAuthorizedAddressAtIndexData, owners[0], @@ -419,9 +421,12 @@ describe('AssetProxyOwner', () => { const submitLog = submitRes.logs[0] as LogWithDecodedArgs<AssetProxyOwnerSubmissionEventArgs>; const txId = submitLog.args.transactionId; - await multiSigWrapper.confirmTransactionAsync(txId, owners[1]); + await assetProxyOwnerWrapper.confirmTransactionAsync(txId, owners[1]); - const execRes = await multiSigWrapper.executeRemoveAuthorizedAddressAtIndexAsync(txId, owners[0]); + const execRes = await assetProxyOwnerWrapper.executeRemoveAuthorizedAddressAtIndexAsync( + txId, + owners[0], + ); const execLog = execRes.logs[1] as LogWithDecodedArgs<AssetProxyOwnerExecutionEventArgs>; expect(execLog.args.transactionId).to.be.bignumber.equal(txId); @@ -441,7 +446,7 @@ describe('AssetProxyOwner', () => { authorized, erc20Index, ); - const submitRes = await multiSigWrapper.submitTransactionAsync( + const submitRes = await assetProxyOwnerWrapper.submitTransactionAsync( erc20Proxy.address, removeAuthorizedAddressAtIndexData, owners[0], @@ -449,9 +454,9 @@ describe('AssetProxyOwner', () => { const submitLog = submitRes.logs[0] as LogWithDecodedArgs<AssetProxyOwnerSubmissionEventArgs>; const txId = submitLog.args.transactionId; - await multiSigWrapper.confirmTransactionAsync(txId, owners[1]); + await assetProxyOwnerWrapper.confirmTransactionAsync(txId, owners[1]); - const execRes = await multiSigWrapper.executeRemoveAuthorizedAddressAtIndexAsync(txId, notOwner); + const execRes = await assetProxyOwnerWrapper.executeRemoveAuthorizedAddressAtIndexAsync(txId, notOwner); const execLog = execRes.logs[1] as LogWithDecodedArgs<AssetProxyOwnerExecutionEventArgs>; expect(execLog.args.transactionId).to.be.bignumber.equal(txId); @@ -468,7 +473,7 @@ describe('AssetProxyOwner', () => { authorized, erc20Index, ); - const submitRes = await multiSigWrapper.submitTransactionAsync( + const submitRes = await assetProxyOwnerWrapper.submitTransactionAsync( erc20Proxy.address, removeAuthorizedAddressAtIndexData, owners[0], @@ -476,9 +481,12 @@ describe('AssetProxyOwner', () => { const submitLog = submitRes.logs[0] as LogWithDecodedArgs<AssetProxyOwnerSubmissionEventArgs>; const txId = submitLog.args.transactionId; - await multiSigWrapper.confirmTransactionAsync(txId, owners[1]); + await assetProxyOwnerWrapper.confirmTransactionAsync(txId, owners[1]); - const execRes = await multiSigWrapper.executeRemoveAuthorizedAddressAtIndexAsync(txId, owners[0]); + const execRes = await assetProxyOwnerWrapper.executeRemoveAuthorizedAddressAtIndexAsync( + txId, + owners[0], + ); const execLog = execRes.logs[1] as LogWithDecodedArgs<AssetProxyOwnerExecutionEventArgs>; expect(execLog.args.transactionId).to.be.bignumber.equal(txId); @@ -495,4 +503,4 @@ describe('AssetProxyOwner', () => { }); }); }); -// tslint:enable:no-unnecessary-type-assertion +// tslint:disable-line max-file-line-count diff --git a/contracts/core/test/tokens/erc721_token.ts b/contracts/core/test/tokens/erc721_token.ts index 72407748f..3b0a5f001 100644 --- a/contracts/core/test/tokens/erc721_token.ts +++ b/contracts/core/test/tokens/erc721_token.ts @@ -1,3 +1,13 @@ +import { + chaiSetup, + constants, + expectTransactionFailedAsync, + expectTransactionFailedWithoutReasonAsync, + LogDecoder, + provider, + txDefaults, + web3Wrapper, +} from '@0x/contracts-test-utils'; import { BlockchainLifecycle } from '@0x/dev-utils'; import { RevertReason } from '@0x/types'; import { BigNumber } from '@0x/utils'; @@ -14,11 +24,6 @@ import { } 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; @@ -53,7 +58,7 @@ describe('ERC721Token', () => { provider, txDefaults, ); - logDecoder = new LogDecoder(web3Wrapper); + logDecoder = new LogDecoder(web3Wrapper, artifacts); await web3Wrapper.awaitTransactionSuccessAsync( await token.mint.sendTransactionAsync(owner, tokenId, { from: owner }), constants.AWAIT_TRANSACTION_MINED_MS, diff --git a/contracts/core/test/tokens/unlimited_allowance_token.ts b/contracts/core/test/tokens/unlimited_allowance_token.ts index ea5a50522..c3e4072c5 100644 --- a/contracts/core/test/tokens/unlimited_allowance_token.ts +++ b/contracts/core/test/tokens/unlimited_allowance_token.ts @@ -1,3 +1,11 @@ +import { + chaiSetup, + constants, + expectContractCallFailedAsync, + provider, + txDefaults, + web3Wrapper, +} from '@0x/contracts-test-utils'; import { BlockchainLifecycle } from '@0x/dev-utils'; import { RevertReason } from '@0x/types'; import { BigNumber } from '@0x/utils'; @@ -5,10 +13,6 @@ 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; diff --git a/contracts/core/test/tokens/weth9.ts b/contracts/core/test/tokens/weth9.ts index 9a31dc3f2..225481904 100644 --- a/contracts/core/test/tokens/weth9.ts +++ b/contracts/core/test/tokens/weth9.ts @@ -1,3 +1,12 @@ +import { + chaiSetup, + constants, + expectInsufficientFundsAsync, + expectTransactionFailedWithoutReasonAsync, + provider, + txDefaults, + web3Wrapper, +} from '@0x/contracts-test-utils'; import { BlockchainLifecycle } from '@0x/dev-utils'; import { BigNumber } from '@0x/utils'; import { Web3Wrapper } from '@0x/web3-wrapper'; @@ -5,10 +14,6 @@ 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; diff --git a/contracts/core/test/tokens/zrx_token.ts b/contracts/core/test/tokens/zrx_token.ts index cab62c205..6bc5e164c 100644 --- a/contracts/core/test/tokens/zrx_token.ts +++ b/contracts/core/test/tokens/zrx_token.ts @@ -1,3 +1,4 @@ +import { chaiSetup, constants, provider, txDefaults, web3Wrapper } from '@0x/contracts-test-utils'; import { BlockchainLifecycle } from '@0x/dev-utils'; import { BigNumber } from '@0x/utils'; import { Web3Wrapper } from '@0x/web3-wrapper'; @@ -5,9 +6,6 @@ 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; diff --git a/contracts/core/test/utils/asset_proxy_owner_wrapper.ts b/contracts/core/test/utils/asset_proxy_owner_wrapper.ts new file mode 100644 index 000000000..d5aaaf519 --- /dev/null +++ b/contracts/core/test/utils/asset_proxy_owner_wrapper.ts @@ -0,0 +1,69 @@ +import { LogDecoder } from '@0x/contracts-test-utils'; +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 { artifacts } from '../../src/artifacts'; + +export class AssetProxyOwnerWrapper { + private readonly _assetProxyOwner: AssetProxyOwnerContract; + private readonly _web3Wrapper: Web3Wrapper; + private readonly _logDecoder: LogDecoder; + constructor(assetproxyOwnerContract: AssetProxyOwnerContract, provider: Provider) { + this._assetProxyOwner = assetproxyOwnerContract; + this._web3Wrapper = new Web3Wrapper(provider); + this._logDecoder = new LogDecoder(this._web3Wrapper, artifacts); + } + 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._assetProxyOwner.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._assetProxyOwner.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._assetProxyOwner.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._assetProxyOwner.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 + ._assetProxyOwner as AssetProxyOwnerContract).executeRemoveAuthorizedAddressAtIndex.sendTransactionAsync( + txId, + { + from, + }, + ); + const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash); + return tx; + } +} diff --git a/contracts/core/test/utils/asset_wrapper.ts b/contracts/core/test/utils/asset_wrapper.ts index 4e7696066..e4090ad74 100644 --- a/contracts/core/test/utils/asset_wrapper.ts +++ b/contracts/core/test/utils/asset_wrapper.ts @@ -1,10 +1,9 @@ +import { AbstractAssetWrapper, constants } from '@0x/contracts-test-utils'; 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'; diff --git a/contracts/core/test/utils/erc20_wrapper.ts b/contracts/core/test/utils/erc20_wrapper.ts index c281a2abf..d6210646c 100644 --- a/contracts/core/test/utils/erc20_wrapper.ts +++ b/contracts/core/test/utils/erc20_wrapper.ts @@ -1,3 +1,4 @@ +import { constants, ERC20BalancesByOwner, txDefaults } from '@0x/contracts-test-utils'; import { assetDataUtils } from '@0x/order-utils'; import { BigNumber } from '@0x/utils'; import { Web3Wrapper } from '@0x/web3-wrapper'; @@ -8,10 +9,6 @@ import { DummyERC20TokenContract } from '../../generated-wrappers/dummy_erc20_to 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; diff --git a/contracts/core/test/utils/erc721_wrapper.ts b/contracts/core/test/utils/erc721_wrapper.ts index e9da553d0..b5ae34e60 100644 --- a/contracts/core/test/utils/erc721_wrapper.ts +++ b/contracts/core/test/utils/erc721_wrapper.ts @@ -1,3 +1,4 @@ +import { constants, ERC721TokenIdsByOwner, txDefaults } from '@0x/contracts-test-utils'; import { generatePseudoRandomSalt } from '@0x/order-utils'; import { BigNumber } from '@0x/utils'; import { Web3Wrapper } from '@0x/web3-wrapper'; @@ -8,10 +9,6 @@ import { DummyERC721TokenContract } from '../../generated-wrappers/dummy_erc721_ 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; diff --git a/contracts/core/test/utils/exchange_wrapper.ts b/contracts/core/test/utils/exchange_wrapper.ts index c28989d3f..2a24b880f 100644 --- a/contracts/core/test/utils/exchange_wrapper.ts +++ b/contracts/core/test/utils/exchange_wrapper.ts @@ -1,14 +1,18 @@ +import { + FillResults, + formatters, + LogDecoder, + OrderInfo, + orderUtils, + SignedTransaction, +} from '@0x/contracts-test-utils'; 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'; +import { artifacts } from '../../src/artifacts'; export class ExchangeWrapper { private readonly _exchange: ExchangeContract; @@ -17,7 +21,7 @@ export class ExchangeWrapper { constructor(exchangeContract: ExchangeContract, provider: Provider) { this._exchange = exchangeContract; this._web3Wrapper = new Web3Wrapper(provider); - this._logDecoder = new LogDecoder(this._web3Wrapper); + this._logDecoder = new LogDecoder(this._web3Wrapper, artifacts); } public async fillOrderAsync( signedOrder: SignedOrder, diff --git a/contracts/core/test/utils/fill_order_combinatorial_utils.ts b/contracts/core/test/utils/fill_order_combinatorial_utils.ts index 8046771f9..6372ad29a 100644 --- a/contracts/core/test/utils/fill_order_combinatorial_utils.ts +++ b/contracts/core/test/utils/fill_order_combinatorial_utils.ts @@ -1,4 +1,21 @@ import { + AllowanceAmountScenario, + AssetDataScenario, + BalanceAmountScenario, + chaiSetup, + constants, + expectTransactionFailedAsync, + ExpirationTimeSecondsScenario, + FeeRecipientAddressScenario, + FillScenario, + OrderAssetAmountScenario, + orderUtils, + signingUtils, + TakerAssetFillAmountScenario, + TakerScenario, + TraderStateScenario, +} from '@0x/contracts-test-utils'; +import { assetDataUtils, BalanceAndProxyAllowanceLazyStore, ExchangeTransferSimulator, @@ -18,30 +35,13 @@ import { ExchangeContract, ExchangeFillEventArgs } from '../../generated-wrapper 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; diff --git a/contracts/core/test/utils/forwarder_wrapper.ts b/contracts/core/test/utils/forwarder_wrapper.ts index a0bfcfe1d..9c5560381 100644 --- a/contracts/core/test/utils/forwarder_wrapper.ts +++ b/contracts/core/test/utils/forwarder_wrapper.ts @@ -1,3 +1,4 @@ +import { constants, formatters, LogDecoder, MarketSellOrders } from '@0x/contracts-test-utils'; import { SignedOrder } from '@0x/types'; import { BigNumber } from '@0x/utils'; import { Web3Wrapper } from '@0x/web3-wrapper'; @@ -5,11 +6,7 @@ import { Provider, TransactionReceiptWithDecodedLogs, TxDataPayable } from 'ethe 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'; +import { artifacts } from '../../src/artifacts'; export class ForwarderWrapper { private readonly _web3Wrapper: Web3Wrapper; @@ -61,7 +58,7 @@ export class ForwarderWrapper { constructor(contractInstance: ForwarderContract, provider: Provider) { this._forwarderContract = contractInstance; this._web3Wrapper = new Web3Wrapper(provider); - this._logDecoder = new LogDecoder(this._web3Wrapper); + this._logDecoder = new LogDecoder(this._web3Wrapper, artifacts); } public async marketSellOrdersWithEthAsync( orders: SignedOrder[], diff --git a/contracts/core/test/utils/match_order_tester.ts b/contracts/core/test/utils/match_order_tester.ts index 6c2c84959..8f574704e 100644 --- a/contracts/core/test/utils/match_order_tester.ts +++ b/contracts/core/test/utils/match_order_tester.ts @@ -1,3 +1,12 @@ +import { + chaiSetup, + ERC20BalancesByOwner, + ERC721TokenIdsByOwner, + OrderInfo, + OrderStatus, + TransferAmountsByMatchOrders as TransferAmounts, + TransferAmountsLoggedByMatchOrders as LoggedTransferAmounts, +} from '@0x/contracts-test-utils'; import { assetDataUtils, orderHashUtils } from '@0x/order-utils'; import { AssetProxyId, SignedOrder } from '@0x/types'; import { BigNumber } from '@0x/utils'; @@ -6,18 +15,9 @@ 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; @@ -270,18 +270,14 @@ export class MatchOrderTester { 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, - ); + expect(leftOrderInfo.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, - ); + expect(rightOrderInfo.orderStatus, 'Checking exchange status for right order').to.be.equal(rightExpectedStatus); } /// @dev Asserts account balances after matching orders. /// @param signedOrderLeft First matched order. diff --git a/contracts/core/test/utils/order_factory_from_scenario.ts b/contracts/core/test/utils/order_factory_from_scenario.ts index 60c8606c4..1cc962020 100644 --- a/contracts/core/test/utils/order_factory_from_scenario.ts +++ b/contracts/core/test/utils/order_factory_from_scenario.ts @@ -1,19 +1,18 @@ -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, + constants, ERC721TokenIdsByOwner, ExpirationTimeSecondsScenario, FeeRecipientAddressScenario, OrderAssetAmountScenario, OrderScenario, TakerScenario, -} from './types'; +} from '@0x/contracts-test-utils'; +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'; 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); diff --git a/contracts/core/tsconfig.json b/contracts/core/tsconfig.json index e0f85079a..82d37b51e 100644 --- a/contracts/core/tsconfig.json +++ b/contracts/core/tsconfig.json @@ -13,6 +13,7 @@ "./generated-artifacts/DummyERC721Token.json", "./generated-artifacts/DummyMultipleReturnERC20Token.json", "./generated-artifacts/DummyNoReturnERC20Token.json", + "./generated-artifacts/DutchAuction.json", "./generated-artifacts/ERC20Proxy.json", "./generated-artifacts/ERC20Token.json", "./generated-artifacts/ERC721Proxy.json", @@ -27,15 +28,11 @@ "./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", diff --git a/contracts/multisig/.solhint.json b/contracts/multisig/.solhint.json new file mode 100644 index 000000000..076afe9f3 --- /dev/null +++ b/contracts/multisig/.solhint.json @@ -0,0 +1,20 @@ +{ + "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/contracts/multisig/CHANGELOG.json b/contracts/multisig/CHANGELOG.json new file mode 100644 index 000000000..fe51488c7 --- /dev/null +++ b/contracts/multisig/CHANGELOG.json @@ -0,0 +1 @@ +[] diff --git a/contracts/multisig/README.md b/contracts/multisig/README.md new file mode 100644 index 000000000..93db63b5b --- /dev/null +++ b/contracts/multisig/README.md @@ -0,0 +1,70 @@ +## MultisSig Contracts + +MultiSig smart contracts + +## Usage + +Contracts can be found in the [contracts](./contracts) directory. The contents of this directory are broken down into the following subdirectories: + +* [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. +* [test](./contracts/test) + * This directory contains mocks and other contracts that are used solely for testing contracts within the other directories. + +## Contributing + +We strongly recommend that the community help us make improvements and determine the future direction of the protocol. To report bugs within this package, please create an issue in this repository. + +For proposals regarding the 0x protocol's smart contract architecture, message format, or additional functionality, go to the [0x Improvement Proposals (ZEIPs)](https://github.com/0xProject/ZEIPs) repository and follow the contribution guidelines provided therein. + +Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started. + +### Install Dependencies + +If you don't have yarn workspaces enabled (Yarn < v1.0) - enable them: + +```bash +yarn config set workspaces-experimental true +``` + +Then install dependencies + +```bash +yarn install +``` + +### Build + +To build this package and all other monorepo packages that it depends on, run the following from the monorepo root directory: + +```bash +PKG=@0x/contracts-multisig yarn build +``` + +Or continuously rebuild on change: + +```bash +PKG=@0x/contracts-multisig yarn watch +``` + +### Clean + +```bash +yarn clean +``` + +### Lint + +```bash +yarn lint +``` + +### Run Tests + +```bash +yarn test +``` + +#### Testing options + +Contracts testing options like coverage, profiling, revert traces or backing node choosing - are described [here](../TESTING.md). diff --git a/contracts/multisig/compiler.json b/contracts/multisig/compiler.json new file mode 100644 index 000000000..5a1f689e2 --- /dev/null +++ b/contracts/multisig/compiler.json @@ -0,0 +1,22 @@ +{ + "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": ["MultiSigWallet", "MultiSigWalletWithTimeLock", "TestRejectEther"] +} diff --git a/contracts/core/contracts/multisig/MultiSigWallet.sol b/contracts/multisig/contracts/multisig/MultiSigWallet.sol index 516e7391c..516e7391c 100644 --- a/contracts/core/contracts/multisig/MultiSigWallet.sol +++ b/contracts/multisig/contracts/multisig/MultiSigWallet.sol diff --git a/contracts/core/contracts/multisig/MultiSigWalletWithTimeLock.sol b/contracts/multisig/contracts/multisig/MultiSigWalletWithTimeLock.sol index 9513d3b30..9513d3b30 100644 --- a/contracts/core/contracts/multisig/MultiSigWalletWithTimeLock.sol +++ b/contracts/multisig/contracts/multisig/MultiSigWalletWithTimeLock.sol diff --git a/contracts/multisig/contracts/test/TestRejectEther/TestRejectEther.sol b/contracts/multisig/contracts/test/TestRejectEther/TestRejectEther.sol new file mode 100644 index 000000000..e523f591d --- /dev/null +++ b/contracts/multisig/contracts/test/TestRejectEther/TestRejectEther.sol @@ -0,0 +1,23 @@ +/* + + 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 no-empty-blocks +contract TestRejectEther {} diff --git a/contracts/multisig/package.json b/contracts/multisig/package.json new file mode 100644 index 000000000..37d064fef --- /dev/null +++ b/contracts/multisig/package.json @@ -0,0 +1,86 @@ +{ + "private": true, + "name": "@0x/contracts-multisig", + "version": "1.0.0", + "engines": { + "node": ">=6.12" + }, + "description": "Multisig contracts used by 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 ../../packages/abi-gen-templates/contract.handlebars --partials '../../packages/abi-gen-templates/partials/**/*.handlebars' --output generated-wrappers --backend ethers", + "lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts", + "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/@(MultiSigWallet|MultiSigWalletWithTimeLock|TestRejectEther).json" + }, + "repository": { + "type": "git", + "url": "https://github.com/0xProject/0x-monorepo.git" + }, + "license": "Apache-2.0", + "bugs": { + "url": "https://github.com/0xProject/0x-monorepo/issues" + }, + "homepage": "https://github.com/0xProject/0x-monorepo/contracts/core/README.md", + "devDependencies": { + "@0x/contracts-test-utils": "^1.0.0", + "@0x/abi-gen": "^1.0.17", + "@0x/dev-utils": "^1.0.18", + "@0x/sol-compiler": "^1.1.13", + "@0x/sol-cov": "^2.1.13", + "@0x/subproviders": "^2.1.5", + "@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.7", + "@0x/order-utils": "^3.0.3", + "@0x/types": "^1.3.0", + "@0x/typescript-typings": "^3.0.4", + "@0x/utils": "^2.0.6", + "@0x/web3-wrapper": "^3.1.5", + "ethereum-types": "^1.1.2", + "lodash": "^4.17.5" + }, + "publishConfig": { + "access": "public" + } +} diff --git a/contracts/multisig/src/artifacts/index.ts b/contracts/multisig/src/artifacts/index.ts new file mode 100644 index 000000000..7cf47be01 --- /dev/null +++ b/contracts/multisig/src/artifacts/index.ts @@ -0,0 +1,11 @@ +import { ContractArtifact } from 'ethereum-types'; + +import * as MultiSigWallet from '../../generated-artifacts/MultiSigWallet.json'; +import * as MultiSigWalletWithTimeLock from '../../generated-artifacts/MultiSigWalletWithTimeLock.json'; +import * as TestRejectEther from '../../generated-artifacts/TestRejectEther.json'; + +export const artifacts = { + TestRejectEther: TestRejectEther as ContractArtifact, + MultiSigWallet: MultiSigWallet as ContractArtifact, + MultiSigWalletWithTimeLock: MultiSigWalletWithTimeLock as ContractArtifact, +}; diff --git a/contracts/multisig/src/wrappers/index.ts b/contracts/multisig/src/wrappers/index.ts new file mode 100644 index 000000000..69abd62f2 --- /dev/null +++ b/contracts/multisig/src/wrappers/index.ts @@ -0,0 +1,2 @@ +export * from '../../generated-wrappers/multi_sig_wallet'; +export * from '../../generated-wrappers/multi_sig_wallet_with_time_lock'; diff --git a/contracts/multisig/test/global_hooks.ts b/contracts/multisig/test/global_hooks.ts new file mode 100644 index 000000000..68eb4f8d5 --- /dev/null +++ b/contracts/multisig/test/global_hooks.ts @@ -0,0 +1,19 @@ +import { env, EnvVars } from '@0x/dev-utils'; + +import { coverage, profiler, provider } from '@0x/contracts-test-utils'; + +before('start web3 provider engine', () => { + provider.start(); +}); + +after('generate coverage report', async () => { + if (env.parseBoolean(EnvVars.SolidityCoverage)) { + const coverageSubprovider = coverage.getCoverageSubproviderSingleton(); + await coverageSubprovider.writeCoverageAsync(); + } + if (env.parseBoolean(EnvVars.SolidityProfiler)) { + const profilerSubprovider = profiler.getProfilerSubproviderSingleton(); + await profilerSubprovider.writeProfilerOutputAsync(); + } + provider.stop(); +}); diff --git a/contracts/core/test/multisig/multi_sig_with_time_lock.ts b/contracts/multisig/test/multi_sig_with_time_lock.ts index 1c0cb0515..31c215505 100644 --- a/contracts/core/test/multisig/multi_sig_with_time_lock.ts +++ b/contracts/multisig/test/multi_sig_with_time_lock.ts @@ -1,3 +1,13 @@ +import { + chaiSetup, + constants, + expectTransactionFailedAsync, + expectTransactionFailedWithoutReasonAsync, + increaseTimeAndMineBlockAsync, + provider, + txDefaults, + web3Wrapper, +} from '@0x/contracts-test-utils'; import { BlockchainLifecycle } from '@0x/dev-utils'; import { RevertReason } from '@0x/types'; import { BigNumber } from '@0x/utils'; @@ -5,7 +15,6 @@ 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, @@ -13,14 +22,11 @@ import { 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'; +} from '../generated-wrappers/multi_sig_wallet_with_time_lock'; +import { TestRejectEtherContract } from '../generated-wrappers/test_reject_ether'; +import { artifacts } from '../src/artifacts'; + +import { MultiSigWrapper } from './utils/multi_sig_wrapper'; chaiSetup.configure(); const expect = chai.expect; @@ -189,14 +195,10 @@ describe('MultiSigWalletWithTimeLock', () => { 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, + const contractWithoutFallback = await TestRejectEtherContract.deployFrom0xArtifactAsync( + artifacts.TestRejectEther, 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); diff --git a/contracts/core/test/utils/multi_sig_wrapper.ts b/contracts/multisig/test/utils/multi_sig_wrapper.ts index 74fd3b4d6..086143613 100644 --- a/contracts/core/test/utils/multi_sig_wrapper.ts +++ b/contracts/multisig/test/utils/multi_sig_wrapper.ts @@ -1,12 +1,11 @@ +import { LogDecoder } from '@0x/contracts-test-utils'; 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'; +import { artifacts } from '../../src/artifacts'; export class MultiSigWrapper { private readonly _multiSig: MultiSigWalletContract; @@ -15,7 +14,7 @@ export class MultiSigWrapper { constructor(multiSigContract: MultiSigWalletContract, provider: Provider) { this._multiSig = multiSigContract; this._web3Wrapper = new Web3Wrapper(provider); - this._logDecoder = new LogDecoder(this._web3Wrapper); + this._logDecoder = new LogDecoder(this._web3Wrapper, artifacts); } public async submitTransactionAsync( destination: string, @@ -52,16 +51,4 @@ export class MultiSigWrapper { 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/contracts/multisig/tsconfig.json b/contracts/multisig/tsconfig.json new file mode 100644 index 000000000..6f381620e --- /dev/null +++ b/contracts/multisig/tsconfig.json @@ -0,0 +1,15 @@ +{ + "extends": "../../tsconfig", + "compilerOptions": { + "outDir": "lib", + "rootDir": ".", + "resolveJsonModule": true + }, + "include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"], + "files": [ + "./generated-artifacts/MultiSigWallet.json", + "./generated-artifacts/MultiSigWalletWithTimeLock.json", + "./generated-artifacts/TestRejectEther.json" + ], + "exclude": ["./deploy/solc/solc_bin"] +} diff --git a/contracts/multisig/tslint.json b/contracts/multisig/tslint.json new file mode 100644 index 000000000..1bb3ac2a2 --- /dev/null +++ b/contracts/multisig/tslint.json @@ -0,0 +1,6 @@ +{ + "extends": ["@0x/tslint-config"], + "rules": { + "custom-no-magic-numbers": false + } +} diff --git a/contracts/test-utils/README.md b/contracts/test-utils/README.md new file mode 100644 index 000000000..73fd93f45 --- /dev/null +++ b/contracts/test-utils/README.md @@ -0,0 +1,73 @@ +## Contracts test utils + +This package contains test utilities used by other smart contracts packages. + +## Usage + +```typescript +import { + chaiSetup, + constants, + expectContractCallFailedAsync, + expectContractCreationFailedAsync, + expectTransactionFailedAsync, + expectTransactionFailedWithoutReasonAsync, + increaseTimeAndMineBlockAsync, + provider, + sendTransactionResult, + txDefaults, + web3Wrapper, +} from '@0x/contracts-test-utils'; +``` + +## 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. + +Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started. + +### Install Dependencies + +If you don't have yarn workspaces enabled (Yarn < v1.0) - enable them: + +```bash +yarn config set workspaces-experimental true +``` + +Then install dependencies + +```bash +yarn install +``` + +### Build + +To build this package and all other monorepo packages that it depends on, run the following from the monorepo root directory: + +```bash +PKG=@0x/contracts-test-utils yarn build +``` + +Or continuously rebuild on change: + +```bash +PKG=@0x/contracts-test-utils yarn watch +``` + +### Clean + +```bash +yarn clean +``` + +### Lint + +```bash +yarn lint +``` + +### Run Tests + +```bash +yarn test +``` diff --git a/contracts/test-utils/package.json b/contracts/test-utils/package.json new file mode 100644 index 000000000..513cfdc10 --- /dev/null +++ b/contracts/test-utils/package.json @@ -0,0 +1,75 @@ +{ + "name": "@0x/contracts-test-utils", + "version": "1.0.0", + "engines": { + "node": ">=6.12" + }, + "description": "Test utils for 0x contracts", + "main": "lib/src/index.js", + "directories": { + "test": "test" + }, + "scripts": { + "build": "tsc -b", + "build:ci": "yarn build", + "test": "yarn run_mocha", + "test:coverage": "run-s build run_mocha coverage:report:text coverage:report:lcov", + "run_mocha": "mocha --require source-map-support/register --require make-promises-safe 'lib/test/**/*.js' --timeout 100000 --bail --exit", + "clean": "shx rm -rf lib", + "lint": "tslint --format stylish --project tsconfig.lint.json", + "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" + }, + "repository": { + "type": "git", + "url": "https://github.com/0xProject/0x-monorepo.git" + }, + "license": "Apache-2.0", + "bugs": { + "url": "https://github.com/0xProject/0x-monorepo/issues" + }, + "homepage": "https://github.com/0xProject/0x-monorepo/contracts/test-utils/README.md", + "devDependencies": { + "mocha": "^4.1.0", + "npm-run-all": "^4.1.2", + "shx": "^0.2.2", + "tslint": "5.11.0", + "typescript": "3.0.1" + }, + "dependencies": { + "@0x/abi-gen": "^1.0.17", + "@0x/dev-utils": "^1.0.18", + "@0x/sol-compiler": "^1.1.13", + "@0x/subproviders": "^2.1.5", + "@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": "*", + "chai": "^4.0.1", + "chai-bignumber": "^2.0.1", + "dirty-chai": "^2.0.1", + "make-promises-safe": "^1.1.0", + "@0x/order-utils": "^3.0.3", + "@0x/types": "^1.3.0", + "@0x/typescript-typings": "^3.0.4", + "@0x/utils": "^2.0.6", + "@0x/sol-cov": "^2.1.13", + "@0x/web3-wrapper": "^3.1.5", + "@types/js-combinatorics": "^0.5.29", + "chai-as-promised": "^7.1.0", + "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/contracts/core/test/utils/abstract_asset_wrapper.ts b/contracts/test-utils/src/abstract_asset_wrapper.ts index 4b56a8502..4b56a8502 100644 --- a/contracts/core/test/utils/abstract_asset_wrapper.ts +++ b/contracts/test-utils/src/abstract_asset_wrapper.ts diff --git a/contracts/core/test/utils/address_utils.ts b/contracts/test-utils/src/address_utils.ts index 634da0c16..634da0c16 100644 --- a/contracts/core/test/utils/address_utils.ts +++ b/contracts/test-utils/src/address_utils.ts diff --git a/contracts/core/test/utils/assertions.ts b/contracts/test-utils/src/assertions.ts index 5b1cedfcc..5b1cedfcc 100644 --- a/contracts/core/test/utils/assertions.ts +++ b/contracts/test-utils/src/assertions.ts diff --git a/contracts/core/test/utils/block_timestamp.ts b/contracts/test-utils/src/block_timestamp.ts index 66c13eed1..66c13eed1 100644 --- a/contracts/core/test/utils/block_timestamp.ts +++ b/contracts/test-utils/src/block_timestamp.ts diff --git a/contracts/core/test/utils/chai_setup.ts b/contracts/test-utils/src/chai_setup.ts index 1a8733093..1a8733093 100644 --- a/contracts/core/test/utils/chai_setup.ts +++ b/contracts/test-utils/src/chai_setup.ts diff --git a/contracts/core/test/utils/combinatorial_utils.ts b/contracts/test-utils/src/combinatorial_utils.ts index bb1b55b4d..bb1b55b4d 100644 --- a/contracts/core/test/utils/combinatorial_utils.ts +++ b/contracts/test-utils/src/combinatorial_utils.ts diff --git a/contracts/core/test/utils/constants.ts b/contracts/test-utils/src/constants.ts index d2c3ab512..d2c3ab512 100644 --- a/contracts/core/test/utils/constants.ts +++ b/contracts/test-utils/src/constants.ts diff --git a/contracts/core/test/utils/coverage.ts b/contracts/test-utils/src/coverage.ts index 5becfa1b6..5becfa1b6 100644 --- a/contracts/core/test/utils/coverage.ts +++ b/contracts/test-utils/src/coverage.ts diff --git a/contracts/core/test/utils/formatters.ts b/contracts/test-utils/src/formatters.ts index 813eb45db..813eb45db 100644 --- a/contracts/core/test/utils/formatters.ts +++ b/contracts/test-utils/src/formatters.ts diff --git a/contracts/test-utils/src/global_hooks.ts b/contracts/test-utils/src/global_hooks.ts new file mode 100644 index 000000000..307dd0777 --- /dev/null +++ b/contracts/test-utils/src/global_hooks.ts @@ -0,0 +1,15 @@ +import { env, EnvVars } from '@0x/dev-utils'; + +import { coverage } from './coverage'; +import { profiler } from './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/contracts/test-utils/src/index.ts b/contracts/test-utils/src/index.ts new file mode 100644 index 000000000..7880de0bf --- /dev/null +++ b/contracts/test-utils/src/index.ts @@ -0,0 +1,55 @@ +export { AbstractAssetWrapper } from './abstract_asset_wrapper'; +export { chaiSetup } from './chai_setup'; +export { constants } from './constants'; +export { + expectContractCallFailedAsync, + expectContractCallFailedWithoutReasonAsync, + expectContractCreationFailedAsync, + expectContractCreationFailedWithoutReasonAsync, + expectInsufficientFundsAsync, + expectTransactionFailedAsync, + sendTransactionResult, + expectTransactionFailedWithoutReasonAsync, + getInvalidOpcodeErrorMessageForCallAsync, + getRevertReasonOrErrorMessageForSendTransactionAsync, +} from './assertions'; +export { getLatestBlockTimestampAsync, increaseTimeAndMineBlockAsync } from './block_timestamp'; +export { provider, txDefaults, web3Wrapper } from './web3_wrapper'; +export { LogDecoder } from './log_decoder'; +export { formatters } from './formatters'; +export { signingUtils } from './signing_utils'; +export { orderUtils } from './order_utils'; +export { typeEncodingUtils } from './type_encoding_utils'; +export { profiler } from './profiler'; +export { coverage } from './coverage'; +export { addressUtils } from './address_utils'; +export { OrderFactory } from './order_factory'; +export { bytes32Values, testCombinatoriallyWithReferenceFuncAsync, uint256Values } from './combinatorial_utils'; +export { TransactionFactory } from './transaction_factory'; +export { testWithReferenceFuncAsync } from './test_with_reference'; +export { + MarketBuyOrders, + MarketSellOrders, + ERC721TokenIdsByOwner, + SignedTransaction, + OrderStatus, + AllowanceAmountScenario, + AssetDataScenario, + BalanceAmountScenario, + ContractName, + ExpirationTimeSecondsScenario, + TransferAmountsLoggedByMatchOrders, + TransferAmountsByMatchOrders, + OrderScenario, + TraderStateScenario, + TransactionDataParams, + Token, + FillScenario, + FeeRecipientAddressScenario, + OrderAssetAmountScenario, + TakerAssetFillAmountScenario, + TakerScenario, + OrderInfo, + ERC20BalancesByOwner, + FillResults, +} from './types'; diff --git a/contracts/core/test/utils/log_decoder.ts b/contracts/test-utils/src/log_decoder.ts index 05b0a9204..54666ea5f 100644 --- a/contracts/core/test/utils/log_decoder.ts +++ b/contracts/test-utils/src/log_decoder.ts @@ -11,8 +11,6 @@ import { } from 'ethereum-types'; import * as _ from 'lodash'; -import { artifacts } from '../../src/artifacts'; - import { constants } from './constants'; export class LogDecoder { @@ -27,7 +25,7 @@ export class LogDecoder { } } } - constructor(web3Wrapper: Web3Wrapper) { + constructor(web3Wrapper: Web3Wrapper, artifacts: { [contractName: string]: ContractArtifact }) { this._web3Wrapper = web3Wrapper; const abiArrays: AbiDefinition[][] = []; _.forEach(artifacts, (artifact: ContractArtifact) => { diff --git a/contracts/core/test/utils/order_factory.ts b/contracts/test-utils/src/order_factory.ts index 2449d1a8a..2449d1a8a 100644 --- a/contracts/core/test/utils/order_factory.ts +++ b/contracts/test-utils/src/order_factory.ts diff --git a/contracts/core/test/utils/order_utils.ts b/contracts/test-utils/src/order_utils.ts index 4f7a34011..4f7a34011 100644 --- a/contracts/core/test/utils/order_utils.ts +++ b/contracts/test-utils/src/order_utils.ts diff --git a/contracts/core/test/utils/profiler.ts b/contracts/test-utils/src/profiler.ts index 2c7c1d66c..2c7c1d66c 100644 --- a/contracts/core/test/utils/profiler.ts +++ b/contracts/test-utils/src/profiler.ts diff --git a/contracts/core/test/utils/revert_trace.ts b/contracts/test-utils/src/revert_trace.ts index 3f74fd28b..3f74fd28b 100644 --- a/contracts/core/test/utils/revert_trace.ts +++ b/contracts/test-utils/src/revert_trace.ts diff --git a/contracts/core/test/utils/signing_utils.ts b/contracts/test-utils/src/signing_utils.ts index 21f864bfa..21f864bfa 100644 --- a/contracts/core/test/utils/signing_utils.ts +++ b/contracts/test-utils/src/signing_utils.ts diff --git a/contracts/core/test/utils/test_with_reference.ts b/contracts/test-utils/src/test_with_reference.ts index b80be4a6c..b80be4a6c 100644 --- a/contracts/core/test/utils/test_with_reference.ts +++ b/contracts/test-utils/src/test_with_reference.ts diff --git a/contracts/core/test/utils/transaction_factory.ts b/contracts/test-utils/src/transaction_factory.ts index dbab3ade4..dbab3ade4 100644 --- a/contracts/core/test/utils/transaction_factory.ts +++ b/contracts/test-utils/src/transaction_factory.ts diff --git a/contracts/core/test/utils/type_encoding_utils.ts b/contracts/test-utils/src/type_encoding_utils.ts index bfd9c9ef5..bfd9c9ef5 100644 --- a/contracts/core/test/utils/type_encoding_utils.ts +++ b/contracts/test-utils/src/type_encoding_utils.ts diff --git a/contracts/core/test/utils/types.ts b/contracts/test-utils/src/types.ts index 9fc9e1570..d738fcd4e 100644 --- a/contracts/core/test/utils/types.ts +++ b/contracts/test-utils/src/types.ts @@ -86,6 +86,7 @@ export enum ContractName { ZRXToken = 'ZRXToken', DummyERC20Token = 'DummyERC20Token', EtherToken = 'WETH9', + DutchAuction = 'DutchAuction', AssetProxyOwner = 'AssetProxyOwner', AccountLevels = 'AccountLevels', EtherDelta = 'EtherDelta', diff --git a/contracts/core/test/utils/web3_wrapper.ts b/contracts/test-utils/src/web3_wrapper.ts index f7b1a732a..cb33476f3 100644 --- a/contracts/core/test/utils/web3_wrapper.ts +++ b/contracts/test-utils/src/web3_wrapper.ts @@ -48,6 +48,7 @@ const ganacheConfigs = { const providerConfigs = testProvider === ProviderType.Ganache ? ganacheConfigs : gethConfigs; export const provider: Web3ProviderEngine = web3Factory.getRpcProvider(providerConfigs); +provider.stop(); const isCoverageEnabled = env.parseBoolean(EnvVars.SolidityCoverage); const isProfilerEnabled = env.parseBoolean(EnvVars.SolidityProfiler); const isRevertTraceEnabled = env.parseBoolean(EnvVars.SolidityRevertTrace); diff --git a/contracts/core/test/utils_test/test_with_reference.ts b/contracts/test-utils/test/test_with_reference.ts index 8d633cd1f..1c1211003 100644 --- a/contracts/core/test/utils_test/test_with_reference.ts +++ b/contracts/test-utils/test/test_with_reference.ts @@ -1,7 +1,7 @@ import * as chai from 'chai'; -import { chaiSetup } from '../utils/chai_setup'; -import { testWithReferenceFuncAsync } from '../utils/test_with_reference'; +import { chaiSetup } from '../src/chai_setup'; +import { testWithReferenceFuncAsync } from '../src/test_with_reference'; chaiSetup.configure(); const expect = chai.expect; diff --git a/contracts/test-utils/tsconfig.json b/contracts/test-utils/tsconfig.json new file mode 100644 index 000000000..e35816553 --- /dev/null +++ b/contracts/test-utils/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "../../tsconfig", + "compilerOptions": { + "outDir": "lib" + }, + "include": ["./src/**/*", "./test/**/*"] +} diff --git a/contracts/test-utils/tsconfig.lint.json b/contracts/test-utils/tsconfig.lint.json new file mode 100644 index 000000000..b557e706a --- /dev/null +++ b/contracts/test-utils/tsconfig.lint.json @@ -0,0 +1,7 @@ +{ + // This file is a workaround that issue: https://github.com/palantir/tslint/issues/4148#issuecomment-419872702 + "extends": "./tsconfig", + "compilerOptions": { + "composite": false + } +} diff --git a/contracts/test-utils/tslint.json b/contracts/test-utils/tslint.json new file mode 100644 index 000000000..1bb3ac2a2 --- /dev/null +++ b/contracts/test-utils/tslint.json @@ -0,0 +1,6 @@ +{ + "extends": ["@0x/tslint-config"], + "rules": { + "custom-no-magic-numbers": false + } +} diff --git a/contracts/utils/.solhint.json b/contracts/utils/.solhint.json new file mode 100644 index 000000000..076afe9f3 --- /dev/null +++ b/contracts/utils/.solhint.json @@ -0,0 +1,20 @@ +{ + "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/contracts/utils/README.md b/contracts/utils/README.md new file mode 100644 index 000000000..e7c7b49ff --- /dev/null +++ b/contracts/utils/README.md @@ -0,0 +1,70 @@ +## Contracts utils + +Smart contracts utils used in the 0x protocol. + +## Usage + +Contracts can be found in the [contracts](./contracts) directory. The contents of this directory are broken down into the following subdirectories: + +* [utils](./contracts/utils) + * This directory contains libraries and utils. +* [test](./contracts/test) + * This directory contains mocks and other contracts that are used solely for testing contracts within the other directories. + +## Contributing + +We strongly recommend that the community help us make improvements and determine the future direction of the protocol. To report bugs within this package, please create an issue in this repository. + +For proposals regarding the 0x protocol's smart contract architecture, message format, or additional functionality, go to the [0x Improvement Proposals (ZEIPs)](https://github.com/0xProject/ZEIPs) repository and follow the contribution guidelines provided therein. + +Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started. + +### Install Dependencies + +If you don't have yarn workspaces enabled (Yarn < v1.0) - enable them: + +```bash +yarn config set workspaces-experimental true +``` + +Then install dependencies + +```bash +yarn install +``` + +### Build + +To build this package and all other monorepo packages that it depends on, run the following from the monorepo root directory: + +```bash +PKG=@0x/contracts-utils yarn build +``` + +Or continuously rebuild on change: + +```bash +PKG=@0x/contracts-utils yarn watch +``` + +### Clean + +```bash +yarn clean +``` + +### Lint + +```bash +yarn lint +``` + +### Run Tests + +```bash +yarn test +``` + +#### Testing options + +Contracts testing options like coverage, profiling, revert traces or backing node choosing - are described [here](../TESTING.md). diff --git a/contracts/utils/compiler.json b/contracts/utils/compiler.json new file mode 100644 index 000000000..1524c1eaa --- /dev/null +++ b/contracts/utils/compiler.json @@ -0,0 +1,22 @@ +{ + "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": ["TestConstants", "TestLibBytes", "LibBytes", "Ownable", "IOwnable", "ReentrancyGuard", "SafeMath"] +} diff --git a/contracts/core/contracts/test/TestConstants/TestConstants.sol b/contracts/utils/contracts/test/TestConstants/TestConstants.sol index 1275d007b..3c852173b 100644 --- a/contracts/core/contracts/test/TestConstants/TestConstants.sol +++ b/contracts/utils/contracts/test/TestConstants/TestConstants.sol @@ -18,7 +18,7 @@ pragma solidity 0.4.24; -import "../../utils/LibBytes/LibBytes.sol"; +import "@0x/contracts-utils/contracts/utils/LibBytes/LibBytes.sol"; // solhint-disable max-line-length diff --git a/contracts/core/contracts/test/TestLibBytes/TestLibBytes.sol b/contracts/utils/contracts/test/TestLibBytes/TestLibBytes.sol index 00d861e61..444a3e717 100644 --- a/contracts/core/contracts/test/TestLibBytes/TestLibBytes.sol +++ b/contracts/utils/contracts/test/TestLibBytes/TestLibBytes.sol @@ -18,7 +18,7 @@ pragma solidity 0.4.24; -import "../../utils/LibBytes/LibBytes.sol"; +import "@0x/contracts-utils/contracts/utils/LibBytes/LibBytes.sol"; contract TestLibBytes { diff --git a/contracts/core/contracts/utils/LibBytes/LibBytes.sol b/contracts/utils/contracts/utils/LibBytes/LibBytes.sol index 369f588ad..369f588ad 100644 --- a/contracts/core/contracts/utils/LibBytes/LibBytes.sol +++ b/contracts/utils/contracts/utils/LibBytes/LibBytes.sol diff --git a/contracts/core/contracts/utils/Ownable/IOwnable.sol b/contracts/utils/contracts/utils/Ownable/IOwnable.sol index 5deb13497..5deb13497 100644 --- a/contracts/core/contracts/utils/Ownable/IOwnable.sol +++ b/contracts/utils/contracts/utils/Ownable/IOwnable.sol diff --git a/contracts/core/contracts/utils/Ownable/Ownable.sol b/contracts/utils/contracts/utils/Ownable/Ownable.sol index 0c830be68..0c830be68 100644 --- a/contracts/core/contracts/utils/Ownable/Ownable.sol +++ b/contracts/utils/contracts/utils/Ownable/Ownable.sol diff --git a/contracts/core/contracts/utils/ReentrancyGuard/ReentrancyGuard.sol b/contracts/utils/contracts/utils/ReentrancyGuard/ReentrancyGuard.sol index 9f98a7a16..9f98a7a16 100644 --- a/contracts/core/contracts/utils/ReentrancyGuard/ReentrancyGuard.sol +++ b/contracts/utils/contracts/utils/ReentrancyGuard/ReentrancyGuard.sol diff --git a/contracts/core/contracts/utils/SafeMath/SafeMath.sol b/contracts/utils/contracts/utils/SafeMath/SafeMath.sol index 2855edb9d..2855edb9d 100644 --- a/contracts/core/contracts/utils/SafeMath/SafeMath.sol +++ b/contracts/utils/contracts/utils/SafeMath/SafeMath.sol diff --git a/contracts/utils/package.json b/contracts/utils/package.json new file mode 100644 index 000000000..c0bc8bfcf --- /dev/null +++ b/contracts/utils/package.json @@ -0,0 +1,90 @@ +{ + "private": true, + "name": "@0x/contracts-utils", + "version": "1.0.0", + "engines": { + "node": ">=6.12" + }, + "description": "Smart contract utils 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/@(IOwnable|Ownable|LibBytes|ReentrancyGuard|SafeMath|TestConstants|TestLibBytes).json" + }, + "repository": { + "type": "git", + "url": "https://github.com/0xProject/0x-monorepo.git" + }, + "license": "Apache-2.0", + "bugs": { + "url": "https://github.com/0xProject/0x-monorepo/issues" + }, + "homepage": "https://github.com/0xProject/0x-monorepo/contracts/utils/README.md", + "devDependencies": { + "@0x/contracts-test-utils": "^1.0.0", + "@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/lodash": "4.14.104", + "@types/node": "*", + "@types/yargs": "^10.0.0", + "bn.js": "^4.11.8", + "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", + "ethereumjs-abi": "0.6.5", + "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/contracts-multisig": "^1.0.0", + "@0x/types": "^1.3.0", + "@0x/typescript-typings": "^3.0.4", + "@0x/utils": "^2.0.6", + "@0x/web3-wrapper": "^3.1.6", + "ethereum-types": "^1.1.2", + "ethereumjs-util": "^5.1.1", + "lodash": "^4.17.5" + }, + "publishConfig": { + "access": "public" + } +} diff --git a/contracts/utils/src/artifacts/index.ts b/contracts/utils/src/artifacts/index.ts new file mode 100644 index 000000000..a5c2b215c --- /dev/null +++ b/contracts/utils/src/artifacts/index.ts @@ -0,0 +1,19 @@ +import { ContractArtifact } from 'ethereum-types'; + +import * as IOwnable from '../../generated-artifacts/IOwnable.json'; +import * as LibBytes from '../../generated-artifacts/LibBytes.json'; +import * as Ownable from '../../generated-artifacts/Ownable.json'; +import * as ReentrancyGuard from '../../generated-artifacts/ReentrancyGuard.json'; +import * as SafeMath from '../../generated-artifacts/SafeMath.json'; +import * as TestConstants from '../../generated-artifacts/TestConstants.json'; +import * as TestLibBytes from '../../generated-artifacts/TestLibBytes.json'; + +export const artifacts = { + TestConstants: TestConstants as ContractArtifact, + TestLibBytes: TestLibBytes as ContractArtifact, + IOwnable: IOwnable as ContractArtifact, + LibBytes: LibBytes as ContractArtifact, + Ownable: Ownable as ContractArtifact, + SafeMath: SafeMath as ContractArtifact, + ReentrancyGuard: ReentrancyGuard as ContractArtifact, +}; diff --git a/contracts/utils/src/index.ts b/contracts/utils/src/index.ts new file mode 100644 index 000000000..d55f08ea2 --- /dev/null +++ b/contracts/utils/src/index.ts @@ -0,0 +1,2 @@ +export * from './artifacts'; +export * from './wrappers'; diff --git a/contracts/utils/src/wrappers/index.ts b/contracts/utils/src/wrappers/index.ts new file mode 100644 index 000000000..823b7fa4b --- /dev/null +++ b/contracts/utils/src/wrappers/index.ts @@ -0,0 +1,2 @@ +export * from '../../generated-wrappers/test_constants'; +export * from '../../generated-wrappers/test_lib_bytes'; diff --git a/contracts/utils/test/global_hooks.ts b/contracts/utils/test/global_hooks.ts new file mode 100644 index 000000000..f8ace376a --- /dev/null +++ b/contracts/utils/test/global_hooks.ts @@ -0,0 +1,17 @@ +import { env, EnvVars } from '@0x/dev-utils'; + +import { coverage, profiler, provider } from '@0x/contracts-test-utils'; +before('start web3 provider', () => { + provider.start(); +}); +after('generate coverage report', async () => { + if (env.parseBoolean(EnvVars.SolidityCoverage)) { + const coverageSubprovider = coverage.getCoverageSubproviderSingleton(); + await coverageSubprovider.writeCoverageAsync(); + } + if (env.parseBoolean(EnvVars.SolidityProfiler)) { + const profilerSubprovider = profiler.getProfilerSubproviderSingleton(); + await profilerSubprovider.writeProfilerOutputAsync(); + } + provider.stop(); +}); diff --git a/contracts/core/test/libraries/lib_bytes.ts b/contracts/utils/test/lib_bytes.ts index b1a389f00..985a98943 100644 --- a/contracts/core/test/libraries/lib_bytes.ts +++ b/contracts/utils/test/lib_bytes.ts @@ -1,3 +1,12 @@ +import { + chaiSetup, + constants, + expectContractCallFailedAsync, + provider, + txDefaults, + typeEncodingUtils, + web3Wrapper, +} from '@0x/contracts-test-utils'; import { BlockchainLifecycle } from '@0x/dev-utils'; import { generatePseudoRandomSalt } from '@0x/order-utils'; import { RevertReason } from '@0x/types'; @@ -7,13 +16,8 @@ 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'; +import { TestLibBytesContract } from '../generated-wrappers/test_lib_bytes'; +import { artifacts } from '../src'; chaiSetup.configure(); const expect = chai.expect; diff --git a/contracts/utils/test/libs.ts b/contracts/utils/test/libs.ts new file mode 100644 index 000000000..81596b2e4 --- /dev/null +++ b/contracts/utils/test/libs.ts @@ -0,0 +1,34 @@ +import { chaiSetup, provider, txDefaults, web3Wrapper } from '@0x/contracts-test-utils'; +import { BlockchainLifecycle } from '@0x/dev-utils'; +import * as chai from 'chai'; + +import { TestConstantsContract } from '../generated-wrappers/test_constants'; +import { artifacts } from '../src'; + +chaiSetup.configure(); +const expect = chai.expect; + +const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); + +describe('Libs', () => { + 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 testConstants = await TestConstantsContract.deployFrom0xArtifactAsync( + artifacts.TestConstants, + provider, + txDefaults, + ); + const isValid = await testConstants.assertValidZrxAssetData.callAsync(); + expect(isValid).to.be.equal(true); + }); + }); + }); +}); diff --git a/contracts/utils/tsconfig.json b/contracts/utils/tsconfig.json new file mode 100644 index 000000000..68251e6b0 --- /dev/null +++ b/contracts/utils/tsconfig.json @@ -0,0 +1,19 @@ +{ + "extends": "../../tsconfig", + "compilerOptions": { + "outDir": "lib", + "rootDir": ".", + "resolveJsonModule": true + }, + "include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"], + "files": [ + "./generated-artifacts/TestConstants.json", + "./generated-artifacts/TestLibBytes.json", + "./generated-artifacts/IOwnable.json", + "./generated-artifacts/Ownable.json", + "./generated-artifacts/LibBytes.json", + "./generated-artifacts/SafeMath.json", + "./generated-artifacts/ReentrancyGuard.json" + ], + "exclude": ["./deploy/solc/solc_bin"] +} diff --git a/contracts/utils/tslint.json b/contracts/utils/tslint.json new file mode 100644 index 000000000..1bb3ac2a2 --- /dev/null +++ b/contracts/utils/tslint.json @@ -0,0 +1,6 @@ +{ + "extends": ["@0x/tslint-config"], + "rules": { + "custom-no-magic-numbers": false + } +} diff --git a/packages/0x.js/.npmignore b/packages/0x.js/.npmignore index d7ee80c97..312a23faa 100644 --- a/packages/0x.js/.npmignore +++ b/packages/0x.js/.npmignore @@ -4,7 +4,7 @@ webpack.config.js yarn-error.log test/ /src/ -/contract_templates/ +/abi-gen-templates/ /generated_docs/ /scripts/ /lib/src/monorepo_scripts/ diff --git a/packages/abi-gen/README.md b/packages/abi-gen/README.md index 20b9d4f30..214d8f257 100644 --- a/packages/abi-gen/README.md +++ b/packages/abi-gen/README.md @@ -4,7 +4,7 @@ This package allows you to generate TypeScript contract wrappers from ABI files. It's heavily inspired by [Geth abigen](https://github.com/ethereum/go-ethereum/wiki/Native-DApps:-Go-bindings-to-Ethereum-contracts) but takes a different approach. You can write your custom handlebars templates which will allow you to seamlessly integrate the generated code into your existing codebase with existing conventions. -[Here](https://github.com/0xProject/0x-monorepo/tree/development/packages/0x.js/contract_templates) are the templates used to generate the contract wrappers used by 0x.js.e +[Here](https://github.com/0xProject/0x-monorepo/tree/development/packages/0x.js/abi-gen-templates) are the templates used to generate the contract wrappers used by 0x.js.e ## Installation @@ -44,7 +44,7 @@ You need to also specify the location of your main template used for every contr ## How to write custom templates? -The best way to get started is to copy [0x.js templates](https://github.com/0xProject/0x-monorepo/tree/development/packages/contract_templates) and start adjusting them for your needs. +The best way to get started is to copy [0x.js templates](https://github.com/0xProject/0x-monorepo/tree/development/packages/abi-gen-templates) and start adjusting them for your needs. We use [handlebars](http://handlebarsjs.com/) template engine under the hood. You need to have a master template called `contract.mustache`. it will be used to generate each contract wrapper. Although - you don't need and probably shouldn't write all your logic in a single template file. You can write [partial templates](http://handlebarsjs.com/partials.html) and as long as they are within a partials folder - they will be registered and available. diff --git a/packages/asset-buyer/CHANGELOG.json b/packages/asset-buyer/CHANGELOG.json index 28d3270e8..4ff83018e 100644 --- a/packages/asset-buyer/CHANGELOG.json +++ b/packages/asset-buyer/CHANGELOG.json @@ -1,5 +1,13 @@ [ { + "version": "3.0.3", + "changes": [ + { + "note": "Update SRA order provider to include Dai" + } + ] + }, + { "timestamp": 1543401373, "version": "3.0.2", "changes": [ diff --git a/packages/asset-buyer/src/order_providers/standard_relayer_api_order_provider.ts b/packages/asset-buyer/src/order_providers/standard_relayer_api_order_provider.ts index be1fc55d6..813c9923b 100644 --- a/packages/asset-buyer/src/order_providers/standard_relayer_api_order_provider.ts +++ b/packages/asset-buyer/src/order_providers/standard_relayer_api_order_provider.ts @@ -100,6 +100,12 @@ export class StandardRelayerAPIOrderProvider implements OrderProvider { } catch (err) { throw new Error(AssetBuyerError.StandardRelayerApiError); } - return _.map(response.records, item => item.assetDataB.assetData); + return _.map(response.records, item => { + if (item.assetDataA.assetData === takerAssetData) { + return item.assetDataB.assetData; + } else { + return item.assetDataA.assetData; + } + }); } } diff --git a/packages/contract-wrappers/.npmignore b/packages/contract-wrappers/.npmignore index 6a3eb57bd..6a222fd45 100644 --- a/packages/contract-wrappers/.npmignore +++ b/packages/contract-wrappers/.npmignore @@ -5,7 +5,7 @@ yarn-error.log test/ /src/ /_bundles/ -/contract_templates/ +/abi-gen-templates/ /generated_docs/ /scripts/ /lib/src/monorepo_scripts/ diff --git a/packages/instant/.dogfood.discharge.json b/packages/instant/.dogfood.discharge.json index 5d6a09a16..651b3daa6 100644 --- a/packages/instant/.dogfood.discharge.json +++ b/packages/instant/.dogfood.discharge.json @@ -1,6 +1,6 @@ { "domain": "0x-instant-dogfood", - "build_command": "WEBPACK_OUTPUT_PATH=public dotenv yarn build --env.discharge_target=dogfood", + "build_command": "WEBPACK_OUTPUT_PATH=public dotenv yarn build -- --env.discharge_target=dogfood", "upload_directory": "public", "index_key": "index.html", "error_key": "index.html", diff --git a/packages/instant/.env_example b/packages/instant/.env_example index ebbbebc06..234e64bbe 100644 --- a/packages/instant/.env_example +++ b/packages/instant/.env_example @@ -1,4 +1,7 @@ INSTANT_ROLLBAR_PUBLISH_TOKEN= INSTANT_ROLLBAR_CLIENT_TOKEN= INSTANT_HEAP_ANALYTICS_ID_PRODUCTION= -INSTANT_HEAP_ANALYTICS_ID_DEVELOPMENT=
\ No newline at end of file +INSTANT_HEAP_ANALYTICS_ID_DEVELOPMENT= +# if you want to report to heap or rollbar when building in development mode, you can use the following: +# INSTANT_HEAP_FORCE_DEVELOPMENT=true +# INSTANT_ROLLBAR_FORCE_DEVELOPMENT=true
\ No newline at end of file diff --git a/packages/instant/.production.discharge.json b/packages/instant/.production.discharge.json index 947f68b1a..1ce39fdd8 100644 --- a/packages/instant/.production.discharge.json +++ b/packages/instant/.production.discharge.json @@ -1,6 +1,6 @@ { "domain": "instant.0xproject.com", - "build_command": "dotenv yarn build --env.discharge_target=production", + "build_command": "dotenv yarn build -- --env.discharge_target=production", "upload_directory": "umd", "index_key": "instant.js", "error_key": "404.html", diff --git a/packages/instant/.staging.discharge.json b/packages/instant/.staging.discharge.json index bd5f28ba8..844e3ca4e 100644 --- a/packages/instant/.staging.discharge.json +++ b/packages/instant/.staging.discharge.json @@ -1,6 +1,6 @@ { "domain": "0x-instant-staging", - "build_command": "dotenv WEBPACK_OUTPUT_PATH=public yarn build --env.discharge_target=staging", + "build_command": "WEBPACK_OUTPUT_PATH=public dotenv yarn build -- --env.discharge_target=staging", "upload_directory": "public", "index_key": "index.html", "error_key": "index.html", diff --git a/packages/instant/src/components/buy_order_progress.tsx b/packages/instant/src/components/buy_order_progress.tsx index 6568de91b..a19f5a4d0 100644 --- a/packages/instant/src/components/buy_order_progress.tsx +++ b/packages/instant/src/components/buy_order_progress.tsx @@ -21,7 +21,7 @@ export const BuyOrderProgress: React.StatelessComponent<BuyOrderProgressProps> = const hasEnded = buyOrderState.processState !== OrderProcessState.Processing; const expectedTimeMs = progress.expectedEndTimeUnix - progress.startTimeUnix; return ( - <Container padding="20px 20px 0px 20px" width="100%"> + <Container width="100%" padding="20px 20px 0px 20px"> <Container marginBottom="5px"> <TimeCounter estimatedTimeMs={expectedTimeMs} hasEnded={hasEnded} key={progress.startTimeUnix} /> </Container> diff --git a/packages/instant/src/components/erc20_asset_amount_input.tsx b/packages/instant/src/components/erc20_asset_amount_input.tsx index ff900842a..4da82eb73 100644 --- a/packages/instant/src/components/erc20_asset_amount_input.tsx +++ b/packages/instant/src/components/erc20_asset_amount_input.tsx @@ -113,7 +113,7 @@ export class ERC20AssetAmountInput extends React.Component<ERC20AssetAmountInput ); }; private readonly _renderChevronIcon = (): React.ReactNode => { - if (!this._areMultipleAssetsAvailable()) { + if (!this._areAnyAssetsAvailable()) { return null; } return ( @@ -134,14 +134,14 @@ export class ERC20AssetAmountInput extends React.Component<ERC20AssetAmountInput // We don't want to allow opening the token selection panel if there are no assets. // Since styles are inferred from the presence of a click handler, we want to return undefined // instead of providing a noop. - if (!this._areMultipleAssetsAvailable() || _.isUndefined(this.props.onSelectAssetClick)) { + if (!this._areAnyAssetsAvailable() || _.isUndefined(this.props.onSelectAssetClick)) { return undefined; } return this._handleSelectAssetClick; }; - private readonly _areMultipleAssetsAvailable = (): boolean => { + private readonly _areAnyAssetsAvailable = (): boolean => { const { numberOfAssetsAvailable } = this.props; - return !_.isUndefined(numberOfAssetsAvailable) && numberOfAssetsAvailable > 1; + return !_.isUndefined(numberOfAssetsAvailable) && numberOfAssetsAvailable > 0; }; private readonly _handleSelectAssetClick = (): void => { if (this.props.onSelectAssetClick) { diff --git a/packages/instant/src/components/instant_heading.tsx b/packages/instant/src/components/instant_heading.tsx index 808c6dc7f..117f9dd5f 100644 --- a/packages/instant/src/components/instant_heading.tsx +++ b/packages/instant/src/components/instant_heading.tsx @@ -32,7 +32,7 @@ export class InstantHeading extends React.Component<InstantHeadingProps, {}> { public render(): React.ReactNode { const iconOrAmounts = this._renderIcon() || this._renderAmountsSection(); return ( - <Container backgroundColor={ColorOption.primaryColor} padding="20px" width="100%"> + <Container backgroundColor={ColorOption.primaryColor} width="100%" padding="20px"> <Container marginBottom="5px"> <Text letterSpacing="1px" diff --git a/packages/instant/src/components/order_details.tsx b/packages/instant/src/components/order_details.tsx index 5fc956e1c..a8e0e2513 100644 --- a/packages/instant/src/components/order_details.tsx +++ b/packages/instant/src/components/order_details.tsx @@ -34,7 +34,7 @@ export class OrderDetails extends React.Component<OrderDetailsProps> { ? assetEthBaseUnitAmount.div(selectedAssetUnitAmount).ceil() : undefined; return ( - <Container padding="20px" width="100%" flexGrow={1}> + <Container width="100%" flexGrow={1} padding="20px 20px 0px 20px"> <Container marginBottom="10px"> <Text letterSpacing="1px" diff --git a/packages/instant/src/components/payment_method.tsx b/packages/instant/src/components/payment_method.tsx index 4efe5b28e..603788748 100644 --- a/packages/instant/src/components/payment_method.tsx +++ b/packages/instant/src/components/payment_method.tsx @@ -26,7 +26,7 @@ export interface PaymentMethodProps { export class PaymentMethod extends React.Component<PaymentMethodProps> { public render(): React.ReactNode { return ( - <Container padding="20px" width="100%" height="133px"> + <Container width="100%" height="120px" padding="20px 20px 0px 20px"> <Container marginBottom="12px"> <Flex justify="space-between"> <Text diff --git a/packages/instant/src/constants.ts b/packages/instant/src/constants.ts index 1194cf881..2439c7349 100644 --- a/packages/instant/src/constants.ts +++ b/packages/instant/src/constants.ts @@ -19,6 +19,7 @@ export const DEFAULT_GAS_PRICE = GWEI_IN_WEI.mul(6); export const DEFAULT_ESTIMATED_TRANSACTION_TIME_MS = ONE_MINUTE_MS * 2; export const ETH_GAS_STATION_API_BASE_URL = 'https://ethgasstation.info'; export const HEAP_ANALYTICS_ID = process.env.HEAP_ANALYTICS_ID; +export const HEAP_ENABLED = process.env.HEAP_ENABLED; export const COINBASE_API_BASE_URL = 'https://api.coinbase.com/v2'; export const PROGRESS_STALL_AT_WIDTH = '95%'; export const PROGRESS_FINISH_ANIMATION_TIME_MS = 200; diff --git a/packages/instant/src/data/asset_meta_data_map.ts b/packages/instant/src/data/asset_meta_data_map.ts index 0553be7f5..88611a8c0 100644 --- a/packages/instant/src/data/asset_meta_data_map.ts +++ b/packages/instant/src/data/asset_meta_data_map.ts @@ -195,7 +195,7 @@ export const assetMetaDataMap: ObjectMap<AssetMetaData> = { '0xf47261b000000000000000000000000089d24a6b4ccb1b6faa2625fe562bdd9a23260359': { assetProxyId: AssetProxyId.ERC20, decimals: 18, - primaryColor: '#F2B350', + primaryColor: '#DEA349', symbol: 'dai', name: 'Dai Stablecoin', }, diff --git a/packages/instant/src/redux/async_data.ts b/packages/instant/src/redux/async_data.ts index 18f671cd7..c67b222d1 100644 --- a/packages/instant/src/redux/async_data.ts +++ b/packages/instant/src/redux/async_data.ts @@ -32,7 +32,8 @@ export const asyncData = { const assetBuyer = providerState.assetBuyer; try { const assetDatas = await assetBuyer.getAvailableAssetDatasAsync(); - const assets = assetUtils.createAssetsFromAssetDatas(assetDatas, assetMetaDataMap, network); + const deduplicatedAssetDatas = _.uniq(assetDatas); + const assets = assetUtils.createAssetsFromAssetDatas(deduplicatedAssetDatas, assetMetaDataMap, network); dispatch(actions.setAvailableAssets(assets)); } catch (e) { const errorMessage = 'Could not find any assets'; diff --git a/packages/instant/src/util/analytics.ts b/packages/instant/src/util/analytics.ts index 4bc4e7c6d..3ab5c55fc 100644 --- a/packages/instant/src/util/analytics.ts +++ b/packages/instant/src/util/analytics.ts @@ -2,7 +2,7 @@ import { BuyQuote } from '@0x/asset-buyer'; import { BigNumber } from '@0x/utils'; import * as _ from 'lodash'; -import { INSTANT_DISCHARGE_TARGET } from '../constants'; +import { HEAP_ENABLED, INSTANT_DISCHARGE_TARGET } from '../constants'; import { AffiliateInfo, Asset, @@ -16,15 +16,17 @@ import { import { EventProperties, heapUtil } from './heap'; -let isDisabled = false; +let isDisabledViaConfig = false; export const disableAnalytics = (shouldDisableAnalytics: boolean) => { - isDisabled = shouldDisableAnalytics; + isDisabledViaConfig = shouldDisableAnalytics; }; export const evaluateIfEnabled = (fnCall: () => void) => { - if (isDisabled) { + if (isDisabledViaConfig) { return; } - fnCall(); + if (HEAP_ENABLED) { + fnCall(); + } }; enum EventNames { diff --git a/packages/instant/webpack.config.js b/packages/instant/webpack.config.js index a1db01db9..e74cf36d9 100644 --- a/packages/instant/webpack.config.js +++ b/packages/instant/webpack.config.js @@ -71,6 +71,7 @@ const generateConfig = (dischargeTarget, heapConfigOptions, rollbarConfigOptions `Must define heap analytics id in ENV var ${heapAnalyticsIdEnvName} when building for ${dischargeTarget}`, ); } + const heapEnabled = heapAnalyticsId && (nodeEnv !== 'development' || process.env.INSTANT_HEAP_FORCE_DEVELOPMENT); const rollbarTokens = getRollbarTokens(dischargeTarget, rollbarConfigOptions.rollbarRequired); const rollbarEnabled = @@ -92,6 +93,7 @@ const generateConfig = (dischargeTarget, heapConfigOptions, rollbarConfigOptions GIT_SHA: JSON.stringify(GIT_SHA), NPM_PACKAGE_VERSION: JSON.stringify(process.env.npm_package_version), ROLLBAR_ENABLED: rollbarEnabled, + HEAP_ENABLED: heapEnabled }; if (dischargeTarget) { envVars.INSTANT_DISCHARGE_TARGET = JSON.stringify(dischargeTarget); diff --git a/packages/monorepo-scripts/CHANGELOG.json b/packages/monorepo-scripts/CHANGELOG.json index 170a97a33..428168437 100644 --- a/packages/monorepo-scripts/CHANGELOG.json +++ b/packages/monorepo-scripts/CHANGELOG.json @@ -13,6 +13,10 @@ { "note": "Add ForwarderError to the IGNORED_EXCESSIVE_TYPES array", "pr": 1147 + }, + { + "note": "Fix a bug when hardcoded CHANGELOG paths cause fetching release notes to fail", + "pr": 1311 } ] }, diff --git a/packages/monorepo-scripts/src/utils/github_release_utils.ts b/packages/monorepo-scripts/src/utils/github_release_utils.ts index 7434d397e..e63244b46 100644 --- a/packages/monorepo-scripts/src/utils/github_release_utils.ts +++ b/packages/monorepo-scripts/src/utils/github_release_utils.ts @@ -41,7 +41,7 @@ export async function publishReleaseNotesAsync(packagesToPublish: Package[], isD let assets: string[] = []; let aggregateNotes = ''; _.each(packagesToPublish, pkg => { - aggregateNotes += getReleaseNotesForPackage(pkg.packageJson.name); + aggregateNotes += getReleaseNotesForPackage(pkg.location, pkg.packageJson.name); const packageAssets = _.get(pkg.packageJson, 'config.postpublish.assets'); if (!_.isUndefined(packageAssets)) { @@ -88,14 +88,8 @@ function adjustAssetPaths(assets: string[]): string[] { return finalAssets; } -function getReleaseNotesForPackage(packageName: string): string { - const packageNameWithoutNamespace = packageName.replace('@0x/', ''); - const changelogJSONPath = path.join( - constants.monorepoRootPath, - 'packages', - packageNameWithoutNamespace, - 'CHANGELOG.json', - ); +function getReleaseNotesForPackage(packageLocation: string, packageName: string): string { + const changelogJSONPath = path.join(packageLocation, 'CHANGELOG.json'); const changelogJSON = readFileSync(changelogJSONPath, 'utf-8'); const changelogs = JSON.parse(changelogJSON); const latestLog = changelogs[0]; diff --git a/packages/sol-compiler/CHANGELOG.json b/packages/sol-compiler/CHANGELOG.json index e9274f64e..fe077b6cc 100644 --- a/packages/sol-compiler/CHANGELOG.json +++ b/packages/sol-compiler/CHANGELOG.json @@ -1,5 +1,14 @@ [ { + "version": "1.1.15", + "changes": [ + { + "note": "Fix bug where we were appending base path to absolute imports (e.g NPM imports)", + "pr": 1311 + } + ] + }, + { "timestamp": 1543401373, "version": "1.1.14", "changes": [ diff --git a/packages/sol-compiler/src/compiler.ts b/packages/sol-compiler/src/compiler.ts index 8ee7fa4a9..cba67f292 100644 --- a/packages/sol-compiler/src/compiler.ts +++ b/packages/sol-compiler/src/compiler.ts @@ -394,7 +394,14 @@ export class Compiler { // const lastPathSeparatorPos = contractPath.lastIndexOf('/'); const contractFolder = lastPathSeparatorPos === -1 ? '' : contractPath.slice(0, lastPathSeparatorPos + 1); - importPath = path.resolve('/' + contractFolder, importPath).replace('/', ''); + if (importPath.startsWith('.')) { + /** + * Some imports path are relative ("../Token.sol", "./Wallet.sol") + * while others are absolute ("Token.sol", "@0x/contracts/Wallet.sol") + * And we need to append the base path for relative imports. + */ + importPath = path.resolve('/' + contractFolder, importPath).replace('/', ''); + } if (_.isUndefined(sourcesToAppendTo[importPath])) { sourcesToAppendTo[importPath] = { id: fullSources[importPath].id }; diff --git a/packages/sol-resolver/CHANGELOG.json b/packages/sol-resolver/CHANGELOG.json index fdfb4009b..4c9e612d7 100644 --- a/packages/sol-resolver/CHANGELOG.json +++ b/packages/sol-resolver/CHANGELOG.json @@ -1,5 +1,14 @@ [ { + "version": "1.1.0", + "changes": [ + { + "note": "NPMResolver now supports scoped packages", + "pr": 1311 + } + ] + }, + { "timestamp": 1542821676, "version": "1.0.17", "changes": [ diff --git a/packages/sol-resolver/src/resolvers/npm_resolver.ts b/packages/sol-resolver/src/resolvers/npm_resolver.ts index a2df0dcad..eeb2b5493 100644 --- a/packages/sol-resolver/src/resolvers/npm_resolver.ts +++ b/packages/sol-resolver/src/resolvers/npm_resolver.ts @@ -1,4 +1,5 @@ import * as fs from 'fs'; +import * as _ from 'lodash'; import * as path from 'path'; import { ContractSource } from '../types'; @@ -13,12 +14,22 @@ export class NPMResolver extends Resolver { } public resolveIfExists(importPath: string): ContractSource | undefined { if (!importPath.startsWith('/')) { - const [packageName, ...other] = importPath.split('/'); + let packageName; + let packageScopeIfExists; + let other; + if (_.startsWith(importPath, '@')) { + [packageScopeIfExists, packageName, ...other] = importPath.split('/'); + } else { + [packageName, ...other] = importPath.split('/'); + } const pathWithinPackage = path.join(...other); let currentPath = this._packagePath; const ROOT_PATH = '/'; while (currentPath !== ROOT_PATH) { - const lookupPath = path.join(currentPath, 'node_modules', packageName, pathWithinPackage); + const packagePath = _.isUndefined(packageScopeIfExists) + ? packageName + : path.join(packageScopeIfExists, packageName); + const lookupPath = path.join(currentPath, 'node_modules', packagePath, pathWithinPackage); if (fs.existsSync(lookupPath) && fs.lstatSync(lookupPath).isFile()) { const fileContent = fs.readFileSync(lookupPath).toString(); return { diff --git a/packages/types/CHANGELOG.json b/packages/types/CHANGELOG.json index 53b24aff0..b09859101 100644 --- a/packages/types/CHANGELOG.json +++ b/packages/types/CHANGELOG.json @@ -5,6 +5,10 @@ { "note": "Add `LengthMismatch` and `LengthGreaterThan3Required` revert reasons", "pr": 1224 + }, + { + "note": "Add RevertReasons for DutchAuction contract", + "pr": 1225 } ] }, diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index 26d8f8e22..6b728af71 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -237,6 +237,12 @@ export enum RevertReason { TxFullyConfirmed = 'TX_FULLY_CONFIRMED', TxNotFullyConfirmed = 'TX_NOT_FULLY_CONFIRMED', TimeLockIncomplete = 'TIME_LOCK_INCOMPLETE', + // DutchAuction + AuctionInvalidAmount = 'INVALID_AMOUNT', + AuctionExpired = 'AUCTION_EXPIRED', + AuctionNotStarted = 'AUCTION_NOT_STARTED', + AuctionInvalidBeginTime = 'INVALID_BEGIN_TIME', + InvalidAssetData = 'INVALID_ASSET_DATA', } export enum StatusCodes { |