diff options
author | fragosti <francesco.agosti93@gmail.com> | 2018-12-06 04:33:34 +0800 |
---|---|---|
committer | fragosti <francesco.agosti93@gmail.com> | 2018-12-06 04:33:34 +0800 |
commit | f9e73d2a6f6b7c3126c0c10286c2f79c4fd2a7ac (patch) | |
tree | e1b93ec089efa842372b885d51046c845728dd75 /contracts/core | |
parent | 5c29b918df4ac8b0f7914e8da10fa1ae530ff4e8 (diff) | |
parent | 08eb0b91b6d0f0dc90ae920a18ca5dd080bf235c (diff) | |
download | dexon-sol-tools-f9e73d2a6f6b7c3126c0c10286c2f79c4fd2a7ac.tar dexon-sol-tools-f9e73d2a6f6b7c3126c0c10286c2f79c4fd2a7ac.tar.gz dexon-sol-tools-f9e73d2a6f6b7c3126c0c10286c2f79c4fd2a7ac.tar.bz2 dexon-sol-tools-f9e73d2a6f6b7c3126c0c10286c2f79c4fd2a7ac.tar.lz dexon-sol-tools-f9e73d2a6f6b7c3126c0c10286c2f79c4fd2a7ac.tar.xz dexon-sol-tools-f9e73d2a6f6b7c3126c0c10286c2f79c4fd2a7ac.tar.zst dexon-sol-tools-f9e73d2a6f6b7c3126c0c10286c2f79c4fd2a7ac.zip |
Merge branch 'development' of https://github.com/0xProject/0x-monorepo into feature/website/instant-configurator
Diffstat (limited to 'contracts/core')
109 files changed, 396 insertions, 5785 deletions
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 a1a60c71d..7e527130a 100644 --- a/contracts/core/compiler.json +++ b/contracts/core/compiler.json @@ -40,15 +40,10 @@ "IWallet", "MixinAuthorizable", "MultiAssetProxy", - "MultiSigWallet", - "MultiSigWalletWithTimeLock", "OrderValidator", "ReentrantERC20Token", "TestAssetProxyOwner", "TestAssetProxyDispatcher", - "TestConstants", - "TestLibBytes", - "TestLibs", "TestExchangeInternals", "TestSignatureValidator", "TestStaticCallReceiver", diff --git a/contracts/core/contracts/examples/ExchangeWrapper/ExchangeWrapper.sol b/contracts/core/contracts/examples/ExchangeWrapper/ExchangeWrapper.sol index 2fa0e3c5e..ca5a64a26 100644 --- a/contracts/core/contracts/examples/ExchangeWrapper/ExchangeWrapper.sol +++ b/contracts/core/contracts/examples/ExchangeWrapper/ExchangeWrapper.sol @@ -20,7 +20,7 @@ pragma solidity 0.4.24; pragma experimental ABIEncoderV2; import "../../protocol/Exchange/interfaces/IExchange.sol"; -import "../../protocol/Exchange/libs/LibOrder.sol"; +import "@0x/contracts-libs/contracts/libs/LibOrder.sol"; contract ExchangeWrapper { 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..cfcddddd3 100644 --- a/contracts/core/contracts/examples/Whitelist/Whitelist.sol +++ b/contracts/core/contracts/examples/Whitelist/Whitelist.sol @@ -20,8 +20,8 @@ pragma solidity 0.4.24; pragma experimental ABIEncoderV2; import "../../protocol/Exchange/interfaces/IExchange.sol"; -import "../../protocol/Exchange/libs/LibOrder.sol"; -import "../../utils/Ownable/Ownable.sol"; +import "@0x/contracts-libs/contracts/libs/LibOrder.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 index abe8309cf..a40991ae7 100644 --- a/contracts/core/contracts/extensions/DutchAuction/DutchAuction.sol +++ b/contracts/core/contracts/extensions/DutchAuction/DutchAuction.sol @@ -20,10 +20,10 @@ pragma solidity 0.4.24; pragma experimental ABIEncoderV2; import "../../protocol/Exchange/interfaces/IExchange.sol"; -import "../../protocol/Exchange/libs/LibOrder.sol"; +import "@0x/contracts-libs/contracts/libs/LibOrder.sol"; import "../../tokens/ERC20Token/IERC20Token.sol"; -import "../../utils/LibBytes/LibBytes.sol"; -import "../../utils/SafeMath/SafeMath.sol"; +import "@0x/contracts-utils/contracts/utils/LibBytes/LibBytes.sol"; +import "@0x/contracts-utils/contracts/utils/SafeMath/SafeMath.sol"; contract DutchAuction is 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/MixinExchangeWrapper.sol b/contracts/core/contracts/extensions/Forwarder/MixinExchangeWrapper.sol index 4991c0ea5..210eb14c2 100644 --- a/contracts/core/contracts/extensions/Forwarder/MixinExchangeWrapper.sol +++ b/contracts/core/contracts/extensions/Forwarder/MixinExchangeWrapper.sol @@ -21,10 +21,10 @@ pragma experimental ABIEncoderV2; import "./libs/LibConstants.sol"; import "./mixins/MExchangeWrapper.sol"; -import "../../protocol/Exchange/libs/LibAbiEncoder.sol"; -import "../../protocol/Exchange/libs/LibOrder.sol"; -import "../../protocol/Exchange/libs/LibFillResults.sol"; -import "../../protocol/Exchange/libs/LibMath.sol"; +import "@0x/contracts-libs/contracts/libs/LibAbiEncoder.sol"; +import "@0x/contracts-libs/contracts/libs/LibOrder.sol"; +import "@0x/contracts-libs/contracts/libs/LibFillResults.sol"; +import "@0x/contracts-libs/contracts/libs/LibMath.sol"; contract MixinExchangeWrapper is diff --git a/contracts/core/contracts/extensions/Forwarder/MixinForwarderCore.sol b/contracts/core/contracts/extensions/Forwarder/MixinForwarderCore.sol index 54487f726..bab78d79b 100644 --- a/contracts/core/contracts/extensions/Forwarder/MixinForwarderCore.sol +++ b/contracts/core/contracts/extensions/Forwarder/MixinForwarderCore.sol @@ -24,10 +24,10 @@ import "./mixins/MWeth.sol"; import "./mixins/MAssets.sol"; import "./mixins/MExchangeWrapper.sol"; import "./interfaces/IForwarderCore.sol"; -import "../../utils/LibBytes/LibBytes.sol"; -import "../../protocol/Exchange/libs/LibOrder.sol"; -import "../../protocol/Exchange/libs/LibFillResults.sol"; -import "../../protocol/Exchange/libs/LibMath.sol"; +import "@0x/contracts-utils/contracts/utils/LibBytes/LibBytes.sol"; +import "@0x/contracts-libs/contracts/libs/LibOrder.sol"; +import "@0x/contracts-libs/contracts/libs/LibFillResults.sol"; +import "@0x/contracts-libs/contracts/libs/LibMath.sol"; contract MixinForwarderCore is diff --git a/contracts/core/contracts/extensions/Forwarder/MixinWeth.sol b/contracts/core/contracts/extensions/Forwarder/MixinWeth.sol index d2814a49b..2a281f3ae 100644 --- a/contracts/core/contracts/extensions/Forwarder/MixinWeth.sol +++ b/contracts/core/contracts/extensions/Forwarder/MixinWeth.sol @@ -18,7 +18,7 @@ pragma solidity 0.4.24; -import "../../protocol/Exchange/libs/LibMath.sol"; +import "@0x/contracts-libs/contracts/libs/LibMath.sol"; import "./libs/LibConstants.sol"; import "./mixins/MWeth.sol"; diff --git a/contracts/core/contracts/extensions/Forwarder/interfaces/IForwarderCore.sol b/contracts/core/contracts/extensions/Forwarder/interfaces/IForwarderCore.sol index 74c7da01d..eede20bb8 100644 --- a/contracts/core/contracts/extensions/Forwarder/interfaces/IForwarderCore.sol +++ b/contracts/core/contracts/extensions/Forwarder/interfaces/IForwarderCore.sol @@ -19,8 +19,8 @@ pragma solidity 0.4.24; pragma experimental ABIEncoderV2; -import "../../../protocol/Exchange/libs/LibOrder.sol"; -import "../../../protocol/Exchange/libs/LibFillResults.sol"; +import "@0x/contracts-libs/contracts/libs/LibOrder.sol"; +import "@0x/contracts-libs/contracts/libs/LibFillResults.sol"; contract IForwarderCore { 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/Forwarder/mixins/MExchangeWrapper.sol b/contracts/core/contracts/extensions/Forwarder/mixins/MExchangeWrapper.sol index 13c26b03a..d9e71786a 100644 --- a/contracts/core/contracts/extensions/Forwarder/mixins/MExchangeWrapper.sol +++ b/contracts/core/contracts/extensions/Forwarder/mixins/MExchangeWrapper.sol @@ -19,8 +19,8 @@ pragma solidity 0.4.24; pragma experimental ABIEncoderV2; -import "../../../protocol/Exchange/libs/LibOrder.sol"; -import "../../../protocol/Exchange/libs/LibFillResults.sol"; +import "@0x/contracts-libs/contracts/libs/LibOrder.sol"; +import "@0x/contracts-libs/contracts/libs/LibFillResults.sol"; contract MExchangeWrapper { diff --git a/contracts/core/contracts/extensions/OrderValidator/OrderValidator.sol b/contracts/core/contracts/extensions/OrderValidator/OrderValidator.sol index 3385d35ef..9e9e63e9b 100644 --- a/contracts/core/contracts/extensions/OrderValidator/OrderValidator.sol +++ b/contracts/core/contracts/extensions/OrderValidator/OrderValidator.sol @@ -20,10 +20,10 @@ pragma solidity 0.4.24; pragma experimental ABIEncoderV2; import "../../protocol/Exchange/interfaces/IExchange.sol"; -import "../../protocol/Exchange/libs/LibOrder.sol"; +import "@0x/contracts-libs/contracts/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/multisig/MultiSigWallet.sol b/contracts/core/contracts/multisig/MultiSigWallet.sol deleted file mode 100644 index 516e7391c..000000000 --- a/contracts/core/contracts/multisig/MultiSigWallet.sol +++ /dev/null @@ -1,393 +0,0 @@ -// solhint-disable -pragma solidity ^0.4.15; - - -/// @title Multisignature wallet - Allows multiple parties to agree on transactions before execution. -/// @author Stefan George - <stefan.george@consensys.net> -contract MultiSigWallet { - - /* - * Events - */ - event Confirmation(address indexed sender, uint indexed transactionId); - event Revocation(address indexed sender, uint indexed transactionId); - event Submission(uint indexed transactionId); - event Execution(uint indexed transactionId); - event ExecutionFailure(uint indexed transactionId); - event Deposit(address indexed sender, uint value); - event OwnerAddition(address indexed owner); - event OwnerRemoval(address indexed owner); - event RequirementChange(uint required); - - /* - * Constants - */ - uint constant public MAX_OWNER_COUNT = 50; - - /* - * Storage - */ - mapping (uint => Transaction) public transactions; - mapping (uint => mapping (address => bool)) public confirmations; - mapping (address => bool) public isOwner; - address[] public owners; - uint public required; - uint public transactionCount; - - struct Transaction { - address destination; - uint value; - bytes data; - bool executed; - } - - /* - * Modifiers - */ - modifier onlyWallet() { - require(msg.sender == address(this)); - _; - } - - modifier ownerDoesNotExist(address owner) { - require(!isOwner[owner]); - _; - } - - modifier ownerExists(address owner) { - require(isOwner[owner]); - _; - } - - modifier transactionExists(uint transactionId) { - require(transactions[transactionId].destination != 0); - _; - } - - modifier confirmed(uint transactionId, address owner) { - require(confirmations[transactionId][owner]); - _; - } - - modifier notConfirmed(uint transactionId, address owner) { - require(!confirmations[transactionId][owner]); - _; - } - - modifier notExecuted(uint transactionId) { - require(!transactions[transactionId].executed); - _; - } - - modifier notNull(address _address) { - require(_address != 0); - _; - } - - modifier validRequirement(uint ownerCount, uint _required) { - require(ownerCount <= MAX_OWNER_COUNT - && _required <= ownerCount - && _required != 0 - && ownerCount != 0); - _; - } - - /// @dev Fallback function allows to deposit ether. - function() - payable - { - if (msg.value > 0) - Deposit(msg.sender, msg.value); - } - - /* - * Public functions - */ - /// @dev Contract constructor sets initial owners and required number of confirmations. - /// @param _owners List of initial owners. - /// @param _required Number of required confirmations. - function MultiSigWallet(address[] _owners, uint _required) - public - validRequirement(_owners.length, _required) - { - for (uint i=0; i<_owners.length; i++) { - require(!isOwner[_owners[i]] && _owners[i] != 0); - isOwner[_owners[i]] = true; - } - owners = _owners; - required = _required; - } - - /// @dev Allows to add a new owner. Transaction has to be sent by wallet. - /// @param owner Address of new owner. - function addOwner(address owner) - public - onlyWallet - ownerDoesNotExist(owner) - notNull(owner) - validRequirement(owners.length + 1, required) - { - isOwner[owner] = true; - owners.push(owner); - OwnerAddition(owner); - } - - /// @dev Allows to remove an owner. Transaction has to be sent by wallet. - /// @param owner Address of owner. - function removeOwner(address owner) - public - onlyWallet - ownerExists(owner) - { - isOwner[owner] = false; - for (uint i=0; i<owners.length - 1; i++) - if (owners[i] == owner) { - owners[i] = owners[owners.length - 1]; - break; - } - owners.length -= 1; - if (required > owners.length) - changeRequirement(owners.length); - OwnerRemoval(owner); - } - - /// @dev Allows to replace an owner with a new owner. Transaction has to be sent by wallet. - /// @param owner Address of owner to be replaced. - /// @param newOwner Address of new owner. - function replaceOwner(address owner, address newOwner) - public - onlyWallet - ownerExists(owner) - ownerDoesNotExist(newOwner) - { - for (uint i=0; i<owners.length; i++) - if (owners[i] == owner) { - owners[i] = newOwner; - break; - } - isOwner[owner] = false; - isOwner[newOwner] = true; - OwnerRemoval(owner); - OwnerAddition(newOwner); - } - - /// @dev Allows to change the number of required confirmations. Transaction has to be sent by wallet. - /// @param _required Number of required confirmations. - function changeRequirement(uint _required) - public - onlyWallet - validRequirement(owners.length, _required) - { - required = _required; - RequirementChange(_required); - } - - /// @dev Allows an owner to submit and confirm a transaction. - /// @param destination Transaction target address. - /// @param value Transaction ether value. - /// @param data Transaction data payload. - /// @return Returns transaction ID. - function submitTransaction(address destination, uint value, bytes data) - public - returns (uint transactionId) - { - transactionId = addTransaction(destination, value, data); - confirmTransaction(transactionId); - } - - /// @dev Allows an owner to confirm a transaction. - /// @param transactionId Transaction ID. - function confirmTransaction(uint transactionId) - public - ownerExists(msg.sender) - transactionExists(transactionId) - notConfirmed(transactionId, msg.sender) - { - confirmations[transactionId][msg.sender] = true; - Confirmation(msg.sender, transactionId); - executeTransaction(transactionId); - } - - /// @dev Allows an owner to revoke a confirmation for a transaction. - /// @param transactionId Transaction ID. - function revokeConfirmation(uint transactionId) - public - ownerExists(msg.sender) - confirmed(transactionId, msg.sender) - notExecuted(transactionId) - { - confirmations[transactionId][msg.sender] = false; - Revocation(msg.sender, transactionId); - } - - /// @dev Allows anyone to execute a confirmed transaction. - /// @param transactionId Transaction ID. - function executeTransaction(uint transactionId) - public - ownerExists(msg.sender) - confirmed(transactionId, msg.sender) - notExecuted(transactionId) - { - if (isConfirmed(transactionId)) { - Transaction storage txn = transactions[transactionId]; - txn.executed = true; - if (external_call(txn.destination, txn.value, txn.data.length, txn.data)) - Execution(transactionId); - else { - ExecutionFailure(transactionId); - txn.executed = false; - } - } - } - - // call has been separated into its own function in order to take advantage - // of the Solidity's code generator to produce a loop that copies tx.data into memory. - function external_call(address destination, uint value, uint dataLength, bytes data) internal returns (bool) { - bool result; - assembly { - let x := mload(0x40) // "Allocate" memory for output (0x40 is where "free memory" pointer is stored by convention) - let d := add(data, 32) // First 32 bytes are the padded length of data, so exclude that - result := call( - sub(gas, 34710), // 34710 is the value that solidity is currently emitting - // It includes callGas (700) + callVeryLow (3, to pay for SUB) + callValueTransferGas (9000) + - // callNewAccountGas (25000, in case the destination address does not exist and needs creating) - destination, - value, - d, - dataLength, // Size of the input (in bytes) - this is what fixes the padding problem - x, - 0 // Output is ignored, therefore the output size is zero - ) - } - return result; - } - - /// @dev Returns the confirmation status of a transaction. - /// @param transactionId Transaction ID. - /// @return Confirmation status. - function isConfirmed(uint transactionId) - public - constant - returns (bool) - { - uint count = 0; - for (uint i=0; i<owners.length; i++) { - if (confirmations[transactionId][owners[i]]) - count += 1; - if (count == required) - return true; - } - } - - /* - * Internal functions - */ - /// @dev Adds a new transaction to the transaction mapping, if transaction does not exist yet. - /// @param destination Transaction target address. - /// @param value Transaction ether value. - /// @param data Transaction data payload. - /// @return Returns transaction ID. - function addTransaction(address destination, uint value, bytes data) - internal - notNull(destination) - returns (uint transactionId) - { - transactionId = transactionCount; - transactions[transactionId] = Transaction({ - destination: destination, - value: value, - data: data, - executed: false - }); - transactionCount += 1; - Submission(transactionId); - } - - /* - * Web3 call functions - */ - /// @dev Returns number of confirmations of a transaction. - /// @param transactionId Transaction ID. - /// @return Number of confirmations. - function getConfirmationCount(uint transactionId) - public - constant - returns (uint count) - { - for (uint i=0; i<owners.length; i++) - if (confirmations[transactionId][owners[i]]) - count += 1; - } - - /// @dev Returns total number of transactions after filers are applied. - /// @param pending Include pending transactions. - /// @param executed Include executed transactions. - /// @return Total number of transactions after filters are applied. - function getTransactionCount(bool pending, bool executed) - public - constant - returns (uint count) - { - for (uint i=0; i<transactionCount; i++) - if ( pending && !transactions[i].executed - || executed && transactions[i].executed) - count += 1; - } - - /// @dev Returns list of owners. - /// @return List of owner addresses. - function getOwners() - public - constant - returns (address[]) - { - return owners; - } - - /// @dev Returns array with owner addresses, which confirmed transaction. - /// @param transactionId Transaction ID. - /// @return Returns array of owner addresses. - function getConfirmations(uint transactionId) - public - constant - returns (address[] _confirmations) - { - address[] memory confirmationsTemp = new address[](owners.length); - uint count = 0; - uint i; - for (i=0; i<owners.length; i++) - if (confirmations[transactionId][owners[i]]) { - confirmationsTemp[count] = owners[i]; - count += 1; - } - _confirmations = new address[](count); - for (i=0; i<count; i++) - _confirmations[i] = confirmationsTemp[i]; - } - - /// @dev Returns list of transaction IDs in defined range. - /// @param from Index start position of transaction array. - /// @param to Index end position of transaction array. - /// @param pending Include pending transactions. - /// @param executed Include executed transactions. - /// @return Returns array of transaction IDs. - function getTransactionIds(uint from, uint to, bool pending, bool executed) - public - constant - returns (uint[] _transactionIds) - { - uint[] memory transactionIdsTemp = new uint[](transactionCount); - uint count = 0; - uint i; - for (i=0; i<transactionCount; i++) - if ( pending && !transactions[i].executed - || executed && transactions[i].executed) - { - transactionIdsTemp[count] = i; - count += 1; - } - _transactionIds = new uint[](to - from); - for (i=from; i<to; i++) - _transactionIds[i - from] = transactionIdsTemp[i]; - } -}
\ No newline at end of file diff --git a/contracts/core/contracts/multisig/MultiSigWalletWithTimeLock.sol b/contracts/core/contracts/multisig/MultiSigWalletWithTimeLock.sol deleted file mode 100644 index 9513d3b30..000000000 --- a/contracts/core/contracts/multisig/MultiSigWalletWithTimeLock.sol +++ /dev/null @@ -1,127 +0,0 @@ -/* - - Copyright 2018 ZeroEx Intl. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - -*/ - -pragma solidity 0.4.24; - -import "./MultiSigWallet.sol"; - - -/// @title Multisignature wallet with time lock- Allows multiple parties to execute a transaction after a time lock has passed. -/// @author Amir Bandeali - <amir@0xProject.com> -// solhint-disable not-rely-on-time -contract MultiSigWalletWithTimeLock is - MultiSigWallet -{ - event ConfirmationTimeSet(uint256 indexed transactionId, uint256 confirmationTime); - event TimeLockChange(uint256 secondsTimeLocked); - - uint256 public secondsTimeLocked; - - mapping (uint256 => uint256) public confirmationTimes; - - modifier notFullyConfirmed(uint256 transactionId) { - require( - !isConfirmed(transactionId), - "TX_FULLY_CONFIRMED" - ); - _; - } - - modifier fullyConfirmed(uint256 transactionId) { - require( - isConfirmed(transactionId), - "TX_NOT_FULLY_CONFIRMED" - ); - _; - } - - modifier pastTimeLock(uint256 transactionId) { - require( - block.timestamp >= confirmationTimes[transactionId] + secondsTimeLocked, - "TIME_LOCK_INCOMPLETE" - ); - _; - } - - /// @dev Contract constructor sets initial owners, required number of confirmations, and time lock. - /// @param _owners List of initial owners. - /// @param _required Number of required confirmations. - /// @param _secondsTimeLocked Duration needed after a transaction is confirmed and before it becomes executable, in seconds. - constructor ( - address[] _owners, - uint256 _required, - uint256 _secondsTimeLocked - ) - public - MultiSigWallet(_owners, _required) - { - secondsTimeLocked = _secondsTimeLocked; - } - - /// @dev Changes the duration of the time lock for transactions. - /// @param _secondsTimeLocked Duration needed after a transaction is confirmed and before it becomes executable, in seconds. - function changeTimeLock(uint256 _secondsTimeLocked) - public - onlyWallet - { - secondsTimeLocked = _secondsTimeLocked; - emit TimeLockChange(_secondsTimeLocked); - } - - /// @dev Allows an owner to confirm a transaction. - /// @param transactionId Transaction ID. - function confirmTransaction(uint256 transactionId) - public - ownerExists(msg.sender) - transactionExists(transactionId) - notConfirmed(transactionId, msg.sender) - notFullyConfirmed(transactionId) - { - confirmations[transactionId][msg.sender] = true; - emit Confirmation(msg.sender, transactionId); - if (isConfirmed(transactionId)) { - setConfirmationTime(transactionId, block.timestamp); - } - } - - /// @dev Allows anyone to execute a confirmed transaction. - /// @param transactionId Transaction ID. - function executeTransaction(uint256 transactionId) - public - notExecuted(transactionId) - fullyConfirmed(transactionId) - pastTimeLock(transactionId) - { - Transaction storage txn = transactions[transactionId]; - txn.executed = true; - if (external_call(txn.destination, txn.value, txn.data.length, txn.data)) { - emit Execution(transactionId); - } else { - emit ExecutionFailure(transactionId); - txn.executed = false; - } - } - - /// @dev Sets the time of when a submission first passed. - function setConfirmationTime(uint256 transactionId, uint256 confirmationTime) - internal - { - confirmationTimes[transactionId] = confirmationTime; - emit ConfirmationTimeSet(transactionId, confirmationTime); - } -} diff --git a/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/AssetProxy/libs/LibAssetProxyErrors.sol b/contracts/core/contracts/protocol/AssetProxy/libs/LibAssetProxyErrors.sol deleted file mode 100644 index 1d9a70cc1..000000000 --- a/contracts/core/contracts/protocol/AssetProxy/libs/LibAssetProxyErrors.sol +++ /dev/null @@ -1,38 +0,0 @@ -/* - - Copyright 2018 ZeroEx Intl. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - -*/ - -// solhint-disable -pragma solidity 0.4.24; - - -/// @dev This contract documents the revert reasons used in the AssetProxy contracts. -/// This contract is intended to serve as a reference, but is not actually used for efficiency reasons. -contract LibAssetProxyErrors { - - /// Authorizable errors /// - string constant SENDER_NOT_AUTHORIZED = "SENDER_NOT_AUTHORIZED"; // Sender not authorized to call this method. - string constant TARGET_NOT_AUTHORIZED = "TARGET_NOT_AUTHORIZED"; // Target address not authorized to call this method. - string constant TARGET_ALREADY_AUTHORIZED = "TARGET_ALREADY_AUTHORIZED"; // Target address must not already be authorized. - string constant INDEX_OUT_OF_BOUNDS = "INDEX_OUT_OF_BOUNDS"; // Specified array index is out of bounds. - string constant AUTHORIZED_ADDRESS_MISMATCH = "AUTHORIZED_ADDRESS_MISMATCH"; // Address at index does not match given target address. - - /// Transfer errors /// - string constant INVALID_AMOUNT = "INVALID_AMOUNT"; // Transfer amount must equal 1. - string constant TRANSFER_FAILED = "TRANSFER_FAILED"; // Transfer failed. - string constant LENGTH_GREATER_THAN_131_REQUIRED = "LENGTH_GREATER_THAN_131_REQUIRED"; // Byte array must have a length greater than 0. -} diff --git a/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/Exchange.sol b/contracts/core/contracts/protocol/Exchange/Exchange.sol index ead36009f..65ca742ea 100644 --- a/contracts/core/contracts/protocol/Exchange/Exchange.sol +++ b/contracts/core/contracts/protocol/Exchange/Exchange.sol @@ -19,7 +19,7 @@ pragma solidity 0.4.24; pragma experimental ABIEncoderV2; -import "./libs/LibConstants.sol"; +import "@0x/contracts-libs/contracts/libs/LibConstants.sol"; import "./MixinExchangeCore.sol"; import "./MixinSignatureValidator.sol"; import "./MixinWrapperFunctions.sol"; 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..68d6a3897 100644 --- a/contracts/core/contracts/protocol/Exchange/MixinExchangeCore.sol +++ b/contracts/core/contracts/protocol/Exchange/MixinExchangeCore.sol @@ -19,11 +19,11 @@ pragma solidity 0.4.24; pragma experimental ABIEncoderV2; -import "../../utils/ReentrancyGuard/ReentrancyGuard.sol"; -import "./libs/LibConstants.sol"; -import "./libs/LibFillResults.sol"; -import "./libs/LibOrder.sol"; -import "./libs/LibMath.sol"; +import "@0x/contracts-utils/contracts/utils/ReentrancyGuard/ReentrancyGuard.sol"; +import "@0x/contracts-libs/contracts/libs/LibConstants.sol"; +import "@0x/contracts-libs/contracts/libs/LibFillResults.sol"; +import "@0x/contracts-libs/contracts/libs/LibOrder.sol"; +import "@0x/contracts-libs/contracts/libs/LibMath.sol"; import "./mixins/MExchangeCore.sol"; import "./mixins/MSignatureValidator.sol"; import "./mixins/MTransactions.sol"; diff --git a/contracts/core/contracts/protocol/Exchange/MixinMatchOrders.sol b/contracts/core/contracts/protocol/Exchange/MixinMatchOrders.sol index b4f6bdb26..fc6d73482 100644 --- a/contracts/core/contracts/protocol/Exchange/MixinMatchOrders.sol +++ b/contracts/core/contracts/protocol/Exchange/MixinMatchOrders.sol @@ -14,11 +14,11 @@ pragma solidity 0.4.24; pragma experimental ABIEncoderV2; -import "../../utils/ReentrancyGuard/ReentrancyGuard.sol"; -import "./libs/LibConstants.sol"; -import "./libs/LibMath.sol"; -import "./libs/LibOrder.sol"; -import "./libs/LibFillResults.sol"; +import "@0x/contracts-utils/contracts/utils/ReentrancyGuard/ReentrancyGuard.sol"; +import "@0x/contracts-libs/contracts/libs/LibConstants.sol"; +import "@0x/contracts-libs/contracts/libs/LibMath.sol"; +import "@0x/contracts-libs/contracts/libs/LibOrder.sol"; +import "@0x/contracts-libs/contracts/libs/LibFillResults.sol"; import "./mixins/MExchangeCore.sol"; import "./mixins/MMatchOrders.sol"; import "./mixins/MTransactions.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/MixinTransactions.sol b/contracts/core/contracts/protocol/Exchange/MixinTransactions.sol index 3a76ca202..87c614382 100644 --- a/contracts/core/contracts/protocol/Exchange/MixinTransactions.sol +++ b/contracts/core/contracts/protocol/Exchange/MixinTransactions.sol @@ -17,10 +17,10 @@ */ pragma solidity 0.4.24; -import "./libs/LibExchangeErrors.sol"; +import "@0x/contracts-libs/contracts/libs/LibExchangeErrors.sol"; import "./mixins/MSignatureValidator.sol"; import "./mixins/MTransactions.sol"; -import "./libs/LibEIP712.sol"; +import "@0x/contracts-libs/contracts/libs/LibEIP712.sol"; contract MixinTransactions is diff --git a/contracts/core/contracts/protocol/Exchange/MixinWrapperFunctions.sol b/contracts/core/contracts/protocol/Exchange/MixinWrapperFunctions.sol index cddff0e5f..2d43432ff 100644 --- a/contracts/core/contracts/protocol/Exchange/MixinWrapperFunctions.sol +++ b/contracts/core/contracts/protocol/Exchange/MixinWrapperFunctions.sol @@ -19,11 +19,11 @@ pragma solidity 0.4.24; pragma experimental ABIEncoderV2; -import "../../utils/ReentrancyGuard/ReentrancyGuard.sol"; -import "./libs/LibMath.sol"; -import "./libs/LibOrder.sol"; -import "./libs/LibFillResults.sol"; -import "./libs/LibAbiEncoder.sol"; +import "@0x/contracts-utils/contracts/utils/ReentrancyGuard/ReentrancyGuard.sol"; +import "@0x/contracts-libs/contracts/libs/LibMath.sol"; +import "@0x/contracts-libs/contracts/libs/LibOrder.sol"; +import "@0x/contracts-libs/contracts/libs/LibFillResults.sol"; +import "@0x/contracts-libs/contracts/libs/LibAbiEncoder.sol"; import "./mixins/MExchangeCore.sol"; import "./mixins/MWrapperFunctions.sol"; diff --git a/contracts/core/contracts/protocol/Exchange/interfaces/IExchangeCore.sol b/contracts/core/contracts/protocol/Exchange/interfaces/IExchangeCore.sol index 9995e0385..0da73529c 100644 --- a/contracts/core/contracts/protocol/Exchange/interfaces/IExchangeCore.sol +++ b/contracts/core/contracts/protocol/Exchange/interfaces/IExchangeCore.sol @@ -19,8 +19,8 @@ pragma solidity 0.4.24; pragma experimental ABIEncoderV2; -import "../libs/LibOrder.sol"; -import "../libs/LibFillResults.sol"; +import "@0x/contracts-libs/contracts/libs/LibOrder.sol"; +import "@0x/contracts-libs/contracts/libs/LibFillResults.sol"; contract IExchangeCore { diff --git a/contracts/core/contracts/protocol/Exchange/interfaces/IMatchOrders.sol b/contracts/core/contracts/protocol/Exchange/interfaces/IMatchOrders.sol index 73447f3ae..b88e158c3 100644 --- a/contracts/core/contracts/protocol/Exchange/interfaces/IMatchOrders.sol +++ b/contracts/core/contracts/protocol/Exchange/interfaces/IMatchOrders.sol @@ -18,8 +18,8 @@ pragma solidity 0.4.24; pragma experimental ABIEncoderV2; -import "../libs/LibOrder.sol"; -import "../libs/LibFillResults.sol"; +import "@0x/contracts-libs/contracts/libs/LibOrder.sol"; +import "@0x/contracts-libs/contracts/libs/LibFillResults.sol"; contract IMatchOrders { diff --git a/contracts/core/contracts/protocol/Exchange/interfaces/IWrapperFunctions.sol b/contracts/core/contracts/protocol/Exchange/interfaces/IWrapperFunctions.sol index 56a533646..833bb7e88 100644 --- a/contracts/core/contracts/protocol/Exchange/interfaces/IWrapperFunctions.sol +++ b/contracts/core/contracts/protocol/Exchange/interfaces/IWrapperFunctions.sol @@ -19,8 +19,8 @@ pragma solidity 0.4.24; pragma experimental ABIEncoderV2; -import "../libs/LibOrder.sol"; -import "../libs/LibFillResults.sol"; +import "@0x/contracts-libs/contracts/libs/LibOrder.sol"; +import "@0x/contracts-libs/contracts/libs/LibFillResults.sol"; contract IWrapperFunctions { diff --git a/contracts/core/contracts/protocol/Exchange/libs/LibAbiEncoder.sol b/contracts/core/contracts/protocol/Exchange/libs/LibAbiEncoder.sol deleted file mode 100644 index 4aad37709..000000000 --- a/contracts/core/contracts/protocol/Exchange/libs/LibAbiEncoder.sol +++ /dev/null @@ -1,215 +0,0 @@ -/* - - Copyright 2018 ZeroEx Intl. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - -*/ - -pragma solidity 0.4.24; -pragma experimental ABIEncoderV2; - -import "./LibOrder.sol"; - - -contract LibAbiEncoder { - - /// @dev ABI encodes calldata for `fillOrder`. - /// @param order Order struct containing order specifications. - /// @param takerAssetFillAmount Desired amount of takerAsset to sell. - /// @param signature Proof that order has been created by maker. - /// @return ABI encoded calldata for `fillOrder`. - function abiEncodeFillOrder( - LibOrder.Order memory order, - uint256 takerAssetFillAmount, - bytes memory signature - ) - internal - pure - returns (bytes memory fillOrderCalldata) - { - // We need to call MExchangeCore.fillOrder using a delegatecall in - // assembly so that we can intercept a call that throws. For this, we - // need the input encoded in memory in the Ethereum ABIv2 format [1]. - - // | Area | Offset | Length | Contents | - // | -------- |--------|---------|-------------------------------------------- | - // | Header | 0x00 | 4 | function selector | - // | Params | | 3 * 32 | function parameters: | - // | | 0x00 | | 1. offset to order (*) | - // | | 0x20 | | 2. takerAssetFillAmount | - // | | 0x40 | | 3. offset to signature (*) | - // | Data | | 12 * 32 | order: | - // | | 0x000 | | 1. senderAddress | - // | | 0x020 | | 2. makerAddress | - // | | 0x040 | | 3. takerAddress | - // | | 0x060 | | 4. feeRecipientAddress | - // | | 0x080 | | 5. makerAssetAmount | - // | | 0x0A0 | | 6. takerAssetAmount | - // | | 0x0C0 | | 7. makerFeeAmount | - // | | 0x0E0 | | 8. takerFeeAmount | - // | | 0x100 | | 9. expirationTimeSeconds | - // | | 0x120 | | 10. salt | - // | | 0x140 | | 11. Offset to makerAssetData (*) | - // | | 0x160 | | 12. Offset to takerAssetData (*) | - // | | 0x180 | 32 | makerAssetData Length | - // | | 0x1A0 | ** | makerAssetData Contents | - // | | 0x1C0 | 32 | takerAssetData Length | - // | | 0x1E0 | ** | takerAssetData Contents | - // | | 0x200 | 32 | signature Length | - // | | 0x220 | ** | signature Contents | - - // * Offsets are calculated from the beginning of the current area: Header, Params, Data: - // An offset stored in the Params area is calculated from the beginning of the Params section. - // An offset stored in the Data area is calculated from the beginning of the Data section. - - // ** The length of dynamic array contents are stored in the field immediately preceeding the contents. - - // [1]: https://solidity.readthedocs.io/en/develop/abi-spec.html - - assembly { - - // Areas below may use the following variables: - // 1. <area>Start -- Start of this area in memory - // 2. <area>End -- End of this area in memory. This value may - // be precomputed (before writing contents), - // or it may be computed as contents are written. - // 3. <area>Offset -- Current offset into area. If an area's End - // is precomputed, this variable tracks the - // offsets of contents as they are written. - - /////// Setup Header Area /////// - // Load free memory pointer - fillOrderCalldata := mload(0x40) - // bytes4(keccak256("fillOrder((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),uint256,bytes)")) - // = 0xb4be83d5 - // Leave 0x20 bytes to store the length - mstore(add(fillOrderCalldata, 0x20), 0xb4be83d500000000000000000000000000000000000000000000000000000000) - let headerAreaEnd := add(fillOrderCalldata, 0x24) - - /////// Setup Params Area /////// - // This area is preallocated and written to later. - // This is because we need to fill in offsets that have not yet been calculated. - let paramsAreaStart := headerAreaEnd - let paramsAreaEnd := add(paramsAreaStart, 0x60) - let paramsAreaOffset := paramsAreaStart - - /////// Setup Data Area /////// - let dataAreaStart := paramsAreaEnd - let dataAreaEnd := dataAreaStart - - // Offset from the source data we're reading from - let sourceOffset := order - // arrayLenBytes and arrayLenWords track the length of a dynamically-allocated bytes array. - let arrayLenBytes := 0 - let arrayLenWords := 0 - - /////// Write order Struct /////// - // Write memory location of Order, relative to the start of the - // parameter list, then increment the paramsAreaOffset respectively. - mstore(paramsAreaOffset, sub(dataAreaEnd, paramsAreaStart)) - paramsAreaOffset := add(paramsAreaOffset, 0x20) - - // Write values for each field in the order - // It would be nice to use a loop, but we save on gas by writing - // the stores sequentially. - mstore(dataAreaEnd, mload(sourceOffset)) // makerAddress - mstore(add(dataAreaEnd, 0x20), mload(add(sourceOffset, 0x20))) // takerAddress - mstore(add(dataAreaEnd, 0x40), mload(add(sourceOffset, 0x40))) // feeRecipientAddress - mstore(add(dataAreaEnd, 0x60), mload(add(sourceOffset, 0x60))) // senderAddress - mstore(add(dataAreaEnd, 0x80), mload(add(sourceOffset, 0x80))) // makerAssetAmount - mstore(add(dataAreaEnd, 0xA0), mload(add(sourceOffset, 0xA0))) // takerAssetAmount - mstore(add(dataAreaEnd, 0xC0), mload(add(sourceOffset, 0xC0))) // makerFeeAmount - mstore(add(dataAreaEnd, 0xE0), mload(add(sourceOffset, 0xE0))) // takerFeeAmount - mstore(add(dataAreaEnd, 0x100), mload(add(sourceOffset, 0x100))) // expirationTimeSeconds - mstore(add(dataAreaEnd, 0x120), mload(add(sourceOffset, 0x120))) // salt - mstore(add(dataAreaEnd, 0x140), mload(add(sourceOffset, 0x140))) // Offset to makerAssetData - mstore(add(dataAreaEnd, 0x160), mload(add(sourceOffset, 0x160))) // Offset to takerAssetData - dataAreaEnd := add(dataAreaEnd, 0x180) - sourceOffset := add(sourceOffset, 0x180) - - // Write offset to <order.makerAssetData> - mstore(add(dataAreaStart, mul(10, 0x20)), sub(dataAreaEnd, dataAreaStart)) - - // Calculate length of <order.makerAssetData> - sourceOffset := mload(add(order, 0x140)) // makerAssetData - arrayLenBytes := mload(sourceOffset) - sourceOffset := add(sourceOffset, 0x20) - arrayLenWords := div(add(arrayLenBytes, 0x1F), 0x20) - - // Write length of <order.makerAssetData> - mstore(dataAreaEnd, arrayLenBytes) - dataAreaEnd := add(dataAreaEnd, 0x20) - - // Write contents of <order.makerAssetData> - for {let i := 0} lt(i, arrayLenWords) {i := add(i, 1)} { - mstore(dataAreaEnd, mload(sourceOffset)) - dataAreaEnd := add(dataAreaEnd, 0x20) - sourceOffset := add(sourceOffset, 0x20) - } - - // Write offset to <order.takerAssetData> - mstore(add(dataAreaStart, mul(11, 0x20)), sub(dataAreaEnd, dataAreaStart)) - - // Calculate length of <order.takerAssetData> - sourceOffset := mload(add(order, 0x160)) // takerAssetData - arrayLenBytes := mload(sourceOffset) - sourceOffset := add(sourceOffset, 0x20) - arrayLenWords := div(add(arrayLenBytes, 0x1F), 0x20) - - // Write length of <order.takerAssetData> - mstore(dataAreaEnd, arrayLenBytes) - dataAreaEnd := add(dataAreaEnd, 0x20) - - // Write contents of <order.takerAssetData> - for {let i := 0} lt(i, arrayLenWords) {i := add(i, 1)} { - mstore(dataAreaEnd, mload(sourceOffset)) - dataAreaEnd := add(dataAreaEnd, 0x20) - sourceOffset := add(sourceOffset, 0x20) - } - - /////// Write takerAssetFillAmount /////// - mstore(paramsAreaOffset, takerAssetFillAmount) - paramsAreaOffset := add(paramsAreaOffset, 0x20) - - /////// Write signature /////// - // Write offset to paramsArea - mstore(paramsAreaOffset, sub(dataAreaEnd, paramsAreaStart)) - - // Calculate length of signature - sourceOffset := signature - arrayLenBytes := mload(sourceOffset) - sourceOffset := add(sourceOffset, 0x20) - arrayLenWords := div(add(arrayLenBytes, 0x1F), 0x20) - - // Write length of signature - mstore(dataAreaEnd, arrayLenBytes) - dataAreaEnd := add(dataAreaEnd, 0x20) - - // Write contents of signature - for {let i := 0} lt(i, arrayLenWords) {i := add(i, 1)} { - mstore(dataAreaEnd, mload(sourceOffset)) - dataAreaEnd := add(dataAreaEnd, 0x20) - sourceOffset := add(sourceOffset, 0x20) - } - - // Set length of calldata - mstore(fillOrderCalldata, sub(dataAreaEnd, add(fillOrderCalldata, 0x20))) - - // Increment free memory pointer - mstore(0x40, dataAreaEnd) - } - - return fillOrderCalldata; - } -} diff --git a/contracts/core/contracts/protocol/Exchange/libs/LibConstants.sol b/contracts/core/contracts/protocol/Exchange/libs/LibConstants.sol deleted file mode 100644 index 8d2732cd3..000000000 --- a/contracts/core/contracts/protocol/Exchange/libs/LibConstants.sol +++ /dev/null @@ -1,49 +0,0 @@ -/* - - Copyright 2018 ZeroEx Intl. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - -*/ - -pragma solidity 0.4.24; - - -// solhint-disable max-line-length -contract LibConstants { - - // Asset data for ZRX token. Used for fee transfers. - // @TODO: Hardcode constant when we deploy. Currently - // not constant to make testing easier. - - // The proxyId for ZRX_ASSET_DATA is bytes4(keccak256("ERC20Token(address)")) = 0xf47261b0 - - // Kovan ZRX address is 0x6ff6c0ff1d68b964901f986d4c9fa3ac68346570. - // The ABI encoded proxyId and address is 0xf47261b00000000000000000000000006ff6c0ff1d68b964901f986d4c9fa3ac68346570 - // bytes constant public ZRX_ASSET_DATA = "\xf4\x72\x61\xb0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x6f\xf6\xc0\xff\x1d\x68\xb9\x64\x90\x1f\x98\x6d\x4c\x9f\xa3\xac\x68\x34\x65\x70"; - - // Mainnet ZRX address is 0xe41d2489571d322189246dafa5ebde1f4699f498. - // The ABI encoded proxyId and address is 0xf47261b0000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f498 - // bytes constant public ZRX_ASSET_DATA = "\xf4\x72\x61\xb0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe4\x1d\x24\x89\x57\x1d\x32\x21\x89\x24\x6d\xaf\xa5\xeb\xde\x1f\x46\x99\xf4\x98"; - - // solhint-disable-next-line var-name-mixedcase - bytes public ZRX_ASSET_DATA; - - // @TODO: Remove when we deploy. - constructor (bytes memory zrxAssetData) - public - { - ZRX_ASSET_DATA = zrxAssetData; - } -} -// solhint-enable max-line-length diff --git a/contracts/core/contracts/protocol/Exchange/libs/LibEIP712.sol b/contracts/core/contracts/protocol/Exchange/libs/LibEIP712.sol deleted file mode 100644 index 203edc1fd..000000000 --- a/contracts/core/contracts/protocol/Exchange/libs/LibEIP712.sol +++ /dev/null @@ -1,87 +0,0 @@ -/* - - Copyright 2018 ZeroEx Intl. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - -*/ - -pragma solidity 0.4.24; - - -contract LibEIP712 { - - // EIP191 header for EIP712 prefix - string constant internal EIP191_HEADER = "\x19\x01"; - - // EIP712 Domain Name value - string constant internal EIP712_DOMAIN_NAME = "0x Protocol"; - - // EIP712 Domain Version value - string constant internal EIP712_DOMAIN_VERSION = "2"; - - // Hash of the EIP712 Domain Separator Schema - bytes32 constant internal EIP712_DOMAIN_SEPARATOR_SCHEMA_HASH = keccak256(abi.encodePacked( - "EIP712Domain(", - "string name,", - "string version,", - "address verifyingContract", - ")" - )); - - // Hash of the EIP712 Domain Separator data - // solhint-disable-next-line var-name-mixedcase - bytes32 public EIP712_DOMAIN_HASH; - - constructor () - public - { - EIP712_DOMAIN_HASH = keccak256(abi.encodePacked( - EIP712_DOMAIN_SEPARATOR_SCHEMA_HASH, - keccak256(bytes(EIP712_DOMAIN_NAME)), - keccak256(bytes(EIP712_DOMAIN_VERSION)), - bytes32(address(this)) - )); - } - - /// @dev Calculates EIP712 encoding for a hash struct in this EIP712 Domain. - /// @param hashStruct The EIP712 hash struct. - /// @return EIP712 hash applied to this EIP712 Domain. - function hashEIP712Message(bytes32 hashStruct) - internal - view - returns (bytes32 result) - { - bytes32 eip712DomainHash = EIP712_DOMAIN_HASH; - - // Assembly for more efficient computing: - // keccak256(abi.encodePacked( - // EIP191_HEADER, - // EIP712_DOMAIN_HASH, - // hashStruct - // )); - - assembly { - // Load free memory pointer - let memPtr := mload(64) - - mstore(memPtr, 0x1901000000000000000000000000000000000000000000000000000000000000) // EIP191 header - mstore(add(memPtr, 2), eip712DomainHash) // EIP712 domain hash - mstore(add(memPtr, 34), hashStruct) // Hash of struct - - // Compute hash - result := keccak256(memPtr, 66) - } - return result; - } -} diff --git a/contracts/core/contracts/protocol/Exchange/libs/LibExchangeErrors.sol b/contracts/core/contracts/protocol/Exchange/libs/LibExchangeErrors.sol deleted file mode 100644 index a0f75bc06..000000000 --- a/contracts/core/contracts/protocol/Exchange/libs/LibExchangeErrors.sol +++ /dev/null @@ -1,70 +0,0 @@ -/* - - Copyright 2018 ZeroEx Intl. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - -*/ - -// solhint-disable -pragma solidity 0.4.24; - - -/// @dev This contract documents the revert reasons used in the Exchange contract. -/// This contract is intended to serve as a reference, but is not actually used for efficiency reasons. -contract LibExchangeErrors { - - /// Order validation errors /// - string constant ORDER_UNFILLABLE = "ORDER_UNFILLABLE"; // Order cannot be filled. - string constant INVALID_MAKER = "INVALID_MAKER"; // Invalid makerAddress. - string constant INVALID_TAKER = "INVALID_TAKER"; // Invalid takerAddress. - string constant INVALID_SENDER = "INVALID_SENDER"; // Invalid `msg.sender`. - string constant INVALID_ORDER_SIGNATURE = "INVALID_ORDER_SIGNATURE"; // Signature validation failed. - - /// fillOrder validation errors /// - string constant INVALID_TAKER_AMOUNT = "INVALID_TAKER_AMOUNT"; // takerAssetFillAmount cannot equal 0. - string constant ROUNDING_ERROR = "ROUNDING_ERROR"; // Rounding error greater than 0.1% of takerAssetFillAmount. - - /// Signature validation errors /// - string constant INVALID_SIGNATURE = "INVALID_SIGNATURE"; // Signature validation failed. - string constant SIGNATURE_ILLEGAL = "SIGNATURE_ILLEGAL"; // Signature type is illegal. - string constant SIGNATURE_UNSUPPORTED = "SIGNATURE_UNSUPPORTED"; // Signature type unsupported. - - /// cancelOrdersUptTo errors /// - string constant INVALID_NEW_ORDER_EPOCH = "INVALID_NEW_ORDER_EPOCH"; // Specified salt must be greater than or equal to existing orderEpoch. - - /// fillOrKillOrder errors /// - string constant COMPLETE_FILL_FAILED = "COMPLETE_FILL_FAILED"; // Desired takerAssetFillAmount could not be completely filled. - - /// matchOrders errors /// - string constant NEGATIVE_SPREAD_REQUIRED = "NEGATIVE_SPREAD_REQUIRED"; // Matched orders must have a negative spread. - - /// Transaction errors /// - string constant REENTRANCY_ILLEGAL = "REENTRANCY_ILLEGAL"; // Recursive reentrancy is not allowed. - string constant INVALID_TX_HASH = "INVALID_TX_HASH"; // Transaction has already been executed. - string constant INVALID_TX_SIGNATURE = "INVALID_TX_SIGNATURE"; // Signature validation failed. - string constant FAILED_EXECUTION = "FAILED_EXECUTION"; // Transaction execution failed. - - /// registerAssetProxy errors /// - string constant ASSET_PROXY_ALREADY_EXISTS = "ASSET_PROXY_ALREADY_EXISTS"; // AssetProxy with same id already exists. - - /// dispatchTransferFrom errors /// - string constant ASSET_PROXY_DOES_NOT_EXIST = "ASSET_PROXY_DOES_NOT_EXIST"; // No assetProxy registered at given id. - string constant TRANSFER_FAILED = "TRANSFER_FAILED"; // Asset transfer unsuccesful. - - /// Length validation errors /// - string constant LENGTH_GREATER_THAN_0_REQUIRED = "LENGTH_GREATER_THAN_0_REQUIRED"; // Byte array must have a length greater than 0. - string constant LENGTH_GREATER_THAN_3_REQUIRED = "LENGTH_GREATER_THAN_3_REQUIRED"; // Byte array must have a length greater than 3. - string constant LENGTH_0_REQUIRED = "LENGTH_0_REQUIRED"; // Byte array must have a length of 0. - string constant LENGTH_65_REQUIRED = "LENGTH_65_REQUIRED"; // Byte array must have a length of 65. -} diff --git a/contracts/core/contracts/protocol/Exchange/libs/LibFillResults.sol b/contracts/core/contracts/protocol/Exchange/libs/LibFillResults.sol deleted file mode 100644 index 659ae9a69..000000000 --- a/contracts/core/contracts/protocol/Exchange/libs/LibFillResults.sol +++ /dev/null @@ -1,53 +0,0 @@ -/* - - Copyright 2018 ZeroEx Intl. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - -*/ - -pragma solidity 0.4.24; - -import "../../../utils/SafeMath/SafeMath.sol"; - - -contract LibFillResults is - SafeMath -{ - struct FillResults { - uint256 makerAssetFilledAmount; // Total amount of makerAsset(s) filled. - uint256 takerAssetFilledAmount; // Total amount of takerAsset(s) filled. - uint256 makerFeePaid; // Total amount of ZRX paid by maker(s) to feeRecipient(s). - uint256 takerFeePaid; // Total amount of ZRX paid by taker to feeRecipients(s). - } - - struct MatchedFillResults { - FillResults left; // Amounts filled and fees paid of left order. - FillResults right; // Amounts filled and fees paid of right order. - uint256 leftMakerAssetSpreadAmount; // Spread between price of left and right order, denominated in the left order's makerAsset, paid to taker. - } - - /// @dev Adds properties of both FillResults instances. - /// Modifies the first FillResults instance specified. - /// @param totalFillResults Fill results instance that will be added onto. - /// @param singleFillResults Fill results instance that will be added to totalFillResults. - function addFillResults(FillResults memory totalFillResults, FillResults memory singleFillResults) - internal - pure - { - totalFillResults.makerAssetFilledAmount = safeAdd(totalFillResults.makerAssetFilledAmount, singleFillResults.makerAssetFilledAmount); - totalFillResults.takerAssetFilledAmount = safeAdd(totalFillResults.takerAssetFilledAmount, singleFillResults.takerAssetFilledAmount); - totalFillResults.makerFeePaid = safeAdd(totalFillResults.makerFeePaid, singleFillResults.makerFeePaid); - totalFillResults.takerFeePaid = safeAdd(totalFillResults.takerFeePaid, singleFillResults.takerFeePaid); - } -} diff --git a/contracts/core/contracts/protocol/Exchange/libs/LibMath.sol b/contracts/core/contracts/protocol/Exchange/libs/LibMath.sol deleted file mode 100644 index c0b85ea10..000000000 --- a/contracts/core/contracts/protocol/Exchange/libs/LibMath.sol +++ /dev/null @@ -1,253 +0,0 @@ -/* - - Copyright 2018 ZeroEx Intl. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - -*/ - -pragma solidity 0.4.24; - -import "../../../utils/SafeMath/SafeMath.sol"; - - -contract LibMath is - SafeMath -{ - /// @dev Calculates partial value given a numerator and denominator rounded down. - /// Reverts if rounding error is >= 0.1% - /// @param numerator Numerator. - /// @param denominator Denominator. - /// @param target Value to calculate partial of. - /// @return Partial value of target rounded down. - function safeGetPartialAmountFloor( - uint256 numerator, - uint256 denominator, - uint256 target - ) - internal - pure - returns (uint256 partialAmount) - { - require( - denominator > 0, - "DIVISION_BY_ZERO" - ); - - require( - !isRoundingErrorFloor( - numerator, - denominator, - target - ), - "ROUNDING_ERROR" - ); - - partialAmount = safeDiv( - safeMul(numerator, target), - denominator - ); - return partialAmount; - } - - /// @dev Calculates partial value given a numerator and denominator rounded down. - /// Reverts if rounding error is >= 0.1% - /// @param numerator Numerator. - /// @param denominator Denominator. - /// @param target Value to calculate partial of. - /// @return Partial value of target rounded up. - function safeGetPartialAmountCeil( - uint256 numerator, - uint256 denominator, - uint256 target - ) - internal - pure - returns (uint256 partialAmount) - { - require( - denominator > 0, - "DIVISION_BY_ZERO" - ); - - require( - !isRoundingErrorCeil( - numerator, - denominator, - target - ), - "ROUNDING_ERROR" - ); - - // safeDiv computes `floor(a / b)`. We use the identity (a, b integer): - // ceil(a / b) = floor((a + b - 1) / b) - // To implement `ceil(a / b)` using safeDiv. - partialAmount = safeDiv( - safeAdd( - safeMul(numerator, target), - safeSub(denominator, 1) - ), - denominator - ); - return partialAmount; - } - - /// @dev Calculates partial value given a numerator and denominator rounded down. - /// @param numerator Numerator. - /// @param denominator Denominator. - /// @param target Value to calculate partial of. - /// @return Partial value of target rounded down. - function getPartialAmountFloor( - uint256 numerator, - uint256 denominator, - uint256 target - ) - internal - pure - returns (uint256 partialAmount) - { - require( - denominator > 0, - "DIVISION_BY_ZERO" - ); - - partialAmount = safeDiv( - safeMul(numerator, target), - denominator - ); - return partialAmount; - } - - /// @dev Calculates partial value given a numerator and denominator rounded down. - /// @param numerator Numerator. - /// @param denominator Denominator. - /// @param target Value to calculate partial of. - /// @return Partial value of target rounded up. - function getPartialAmountCeil( - uint256 numerator, - uint256 denominator, - uint256 target - ) - internal - pure - returns (uint256 partialAmount) - { - require( - denominator > 0, - "DIVISION_BY_ZERO" - ); - - // safeDiv computes `floor(a / b)`. We use the identity (a, b integer): - // ceil(a / b) = floor((a + b - 1) / b) - // To implement `ceil(a / b)` using safeDiv. - partialAmount = safeDiv( - safeAdd( - safeMul(numerator, target), - safeSub(denominator, 1) - ), - denominator - ); - return partialAmount; - } - - /// @dev Checks if rounding error >= 0.1% when rounding down. - /// @param numerator Numerator. - /// @param denominator Denominator. - /// @param target Value to multiply with numerator/denominator. - /// @return Rounding error is present. - function isRoundingErrorFloor( - uint256 numerator, - uint256 denominator, - uint256 target - ) - internal - pure - returns (bool isError) - { - require( - denominator > 0, - "DIVISION_BY_ZERO" - ); - - // The absolute rounding error is the difference between the rounded - // value and the ideal value. The relative rounding error is the - // absolute rounding error divided by the absolute value of the - // ideal value. This is undefined when the ideal value is zero. - // - // The ideal value is `numerator * target / denominator`. - // Let's call `numerator * target % denominator` the remainder. - // The absolute error is `remainder / denominator`. - // - // When the ideal value is zero, we require the absolute error to - // be zero. Fortunately, this is always the case. The ideal value is - // zero iff `numerator == 0` and/or `target == 0`. In this case the - // remainder and absolute error are also zero. - if (target == 0 || numerator == 0) { - return false; - } - - // Otherwise, we want the relative rounding error to be strictly - // less than 0.1%. - // The relative error is `remainder / (numerator * target)`. - // We want the relative error less than 1 / 1000: - // remainder / (numerator * denominator) < 1 / 1000 - // or equivalently: - // 1000 * remainder < numerator * target - // so we have a rounding error iff: - // 1000 * remainder >= numerator * target - uint256 remainder = mulmod( - target, - numerator, - denominator - ); - isError = safeMul(1000, remainder) >= safeMul(numerator, target); - return isError; - } - - /// @dev Checks if rounding error >= 0.1% when rounding up. - /// @param numerator Numerator. - /// @param denominator Denominator. - /// @param target Value to multiply with numerator/denominator. - /// @return Rounding error is present. - function isRoundingErrorCeil( - uint256 numerator, - uint256 denominator, - uint256 target - ) - internal - pure - returns (bool isError) - { - require( - denominator > 0, - "DIVISION_BY_ZERO" - ); - - // See the comments in `isRoundingError`. - if (target == 0 || numerator == 0) { - // When either is zero, the ideal value and rounded value are zero - // and there is no rounding error. (Although the relative error - // is undefined.) - return false; - } - // Compute remainder as before - uint256 remainder = mulmod( - target, - numerator, - denominator - ); - remainder = safeSub(denominator, remainder) % denominator; - isError = safeMul(1000, remainder) >= safeMul(numerator, target); - return isError; - } -} diff --git a/contracts/core/contracts/protocol/Exchange/libs/LibOrder.sol b/contracts/core/contracts/protocol/Exchange/libs/LibOrder.sol deleted file mode 100644 index 0fe7c2161..000000000 --- a/contracts/core/contracts/protocol/Exchange/libs/LibOrder.sol +++ /dev/null @@ -1,145 +0,0 @@ -/* - - Copyright 2018 ZeroEx Intl. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - -*/ - -pragma solidity 0.4.24; - -import "./LibEIP712.sol"; - - -contract LibOrder is - LibEIP712 -{ - // Hash for the EIP712 Order Schema - bytes32 constant internal EIP712_ORDER_SCHEMA_HASH = keccak256(abi.encodePacked( - "Order(", - "address makerAddress,", - "address takerAddress,", - "address feeRecipientAddress,", - "address senderAddress,", - "uint256 makerAssetAmount,", - "uint256 takerAssetAmount,", - "uint256 makerFee,", - "uint256 takerFee,", - "uint256 expirationTimeSeconds,", - "uint256 salt,", - "bytes makerAssetData,", - "bytes takerAssetData", - ")" - )); - - // A valid order remains fillable until it is expired, fully filled, or cancelled. - // An order's state is unaffected by external factors, like account balances. - enum OrderStatus { - INVALID, // Default value - INVALID_MAKER_ASSET_AMOUNT, // Order does not have a valid maker asset amount - INVALID_TAKER_ASSET_AMOUNT, // Order does not have a valid taker asset amount - FILLABLE, // Order is fillable - EXPIRED, // Order has already expired - FULLY_FILLED, // Order is fully filled - CANCELLED // Order has been cancelled - } - - // solhint-disable max-line-length - struct Order { - address makerAddress; // Address that created the order. - address takerAddress; // Address that is allowed to fill the order. If set to 0, any address is allowed to fill the order. - address feeRecipientAddress; // Address that will recieve fees when order is filled. - address senderAddress; // Address that is allowed to call Exchange contract methods that affect this order. If set to 0, any address is allowed to call these methods. - uint256 makerAssetAmount; // Amount of makerAsset being offered by maker. Must be greater than 0. - uint256 takerAssetAmount; // Amount of takerAsset being bid on by maker. Must be greater than 0. - uint256 makerFee; // Amount of ZRX paid to feeRecipient by maker when order is filled. If set to 0, no transfer of ZRX from maker to feeRecipient will be attempted. - uint256 takerFee; // Amount of ZRX paid to feeRecipient by taker when order is filled. If set to 0, no transfer of ZRX from taker to feeRecipient will be attempted. - uint256 expirationTimeSeconds; // Timestamp in seconds at which order expires. - uint256 salt; // Arbitrary number to facilitate uniqueness of the order's hash. - bytes makerAssetData; // Encoded data that can be decoded by a specified proxy contract when transferring makerAsset. The last byte references the id of this proxy. - bytes takerAssetData; // Encoded data that can be decoded by a specified proxy contract when transferring takerAsset. The last byte references the id of this proxy. - } - // solhint-enable max-line-length - - struct OrderInfo { - uint8 orderStatus; // Status that describes order's validity and fillability. - bytes32 orderHash; // EIP712 hash of the order (see LibOrder.getOrderHash). - uint256 orderTakerAssetFilledAmount; // Amount of order that has already been filled. - } - - /// @dev Calculates Keccak-256 hash of the order. - /// @param order The order structure. - /// @return Keccak-256 EIP712 hash of the order. - function getOrderHash(Order memory order) - internal - view - returns (bytes32 orderHash) - { - orderHash = hashEIP712Message(hashOrder(order)); - return orderHash; - } - - /// @dev Calculates EIP712 hash of the order. - /// @param order The order structure. - /// @return EIP712 hash of the order. - function hashOrder(Order memory order) - internal - pure - returns (bytes32 result) - { - bytes32 schemaHash = EIP712_ORDER_SCHEMA_HASH; - bytes32 makerAssetDataHash = keccak256(order.makerAssetData); - bytes32 takerAssetDataHash = keccak256(order.takerAssetData); - - // Assembly for more efficiently computing: - // keccak256(abi.encodePacked( - // EIP712_ORDER_SCHEMA_HASH, - // bytes32(order.makerAddress), - // bytes32(order.takerAddress), - // bytes32(order.feeRecipientAddress), - // bytes32(order.senderAddress), - // order.makerAssetAmount, - // order.takerAssetAmount, - // order.makerFee, - // order.takerFee, - // order.expirationTimeSeconds, - // order.salt, - // keccak256(order.makerAssetData), - // keccak256(order.takerAssetData) - // )); - - assembly { - // Calculate memory addresses that will be swapped out before hashing - let pos1 := sub(order, 32) - let pos2 := add(order, 320) - let pos3 := add(order, 352) - - // Backup - let temp1 := mload(pos1) - let temp2 := mload(pos2) - let temp3 := mload(pos3) - - // Hash in place - mstore(pos1, schemaHash) - mstore(pos2, makerAssetDataHash) - mstore(pos3, takerAssetDataHash) - result := keccak256(pos1, 416) - - // Restore - mstore(pos1, temp1) - mstore(pos2, temp2) - mstore(pos3, temp3) - } - return result; - } -} diff --git a/contracts/core/contracts/protocol/Exchange/mixins/MExchangeCore.sol b/contracts/core/contracts/protocol/Exchange/mixins/MExchangeCore.sol index 742499568..099bdcc33 100644 --- a/contracts/core/contracts/protocol/Exchange/mixins/MExchangeCore.sol +++ b/contracts/core/contracts/protocol/Exchange/mixins/MExchangeCore.sol @@ -19,8 +19,8 @@ pragma solidity 0.4.24; pragma experimental ABIEncoderV2; -import "../libs/LibOrder.sol"; -import "../libs/LibFillResults.sol"; +import "@0x/contracts-libs/contracts/libs/LibOrder.sol"; +import "@0x/contracts-libs/contracts/libs/LibFillResults.sol"; import "../interfaces/IExchangeCore.sol"; diff --git a/contracts/core/contracts/protocol/Exchange/mixins/MMatchOrders.sol b/contracts/core/contracts/protocol/Exchange/mixins/MMatchOrders.sol index 96fa34bc0..bb285de03 100644 --- a/contracts/core/contracts/protocol/Exchange/mixins/MMatchOrders.sol +++ b/contracts/core/contracts/protocol/Exchange/mixins/MMatchOrders.sol @@ -18,8 +18,8 @@ pragma solidity 0.4.24; pragma experimental ABIEncoderV2; -import "../libs/LibOrder.sol"; -import "../libs/LibFillResults.sol"; +import "@0x/contracts-libs/contracts/libs/LibOrder.sol"; +import "@0x/contracts-libs/contracts/libs/LibFillResults.sol"; import "../interfaces/IMatchOrders.sol"; diff --git a/contracts/core/contracts/protocol/Exchange/mixins/MWrapperFunctions.sol b/contracts/core/contracts/protocol/Exchange/mixins/MWrapperFunctions.sol index 4adfbde01..2d21bf057 100644 --- a/contracts/core/contracts/protocol/Exchange/mixins/MWrapperFunctions.sol +++ b/contracts/core/contracts/protocol/Exchange/mixins/MWrapperFunctions.sol @@ -19,8 +19,8 @@ pragma solidity 0.4.24; pragma experimental ABIEncoderV2; -import "../libs/LibOrder.sol"; -import "../libs/LibFillResults.sol"; +import "@0x/contracts-libs/contracts/libs/LibOrder.sol"; +import "@0x/contracts-libs/contracts/libs/LibFillResults.sol"; import "../interfaces/IWrapperFunctions.sol"; 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..8e077e3e8 100644 --- a/contracts/core/contracts/test/ReentrantERC20Token/ReentrantERC20Token.sol +++ b/contracts/core/contracts/test/ReentrantERC20Token/ReentrantERC20Token.sol @@ -19,10 +19,10 @@ 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"; +import "@0x/contracts-libs/contracts/libs/LibOrder.sol"; // solhint-disable no-unused-vars diff --git a/contracts/core/contracts/test/TestConstants/TestConstants.sol b/contracts/core/contracts/test/TestConstants/TestConstants.sol deleted file mode 100644 index 1275d007b..000000000 --- a/contracts/core/contracts/test/TestConstants/TestConstants.sol +++ /dev/null @@ -1,57 +0,0 @@ -/* - - Copyright 2018 ZeroEx Intl. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - -*/ - -pragma solidity 0.4.24; - -import "../../utils/LibBytes/LibBytes.sol"; - - -// solhint-disable max-line-length -contract TestConstants { - - using LibBytes for bytes; - - bytes4 constant internal ERC20_PROXY_ID = bytes4(keccak256("ERC20Token(address)")); - - address constant internal KOVAN_ZRX_ADDRESS = 0x6Ff6C0Ff1d68b964901F986d4C9FA3ac68346570; - bytes constant internal KOVAN_ZRX_ASSET_DATA = "\xf4\x72\x61\xb0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x6f\xf6\xc0\xff\x1d\x68\xb9\x64\x90\x1f\x98\x6d\x4c\x9f\xa3\xac\x68\x34\x65\x70"; - - address constant internal MAINNET_ZRX_ADDRESS = 0xE41d2489571d322189246DaFA5ebDe1F4699F498; - bytes constant public MAINNET_ZRX_ASSET_DATA = "\xf4\x72\x61\xb0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe4\x1d\x24\x89\x57\x1d\x32\x21\x89\x24\x6d\xaf\xa5\xeb\xde\x1f\x46\x99\xf4\x98"; - - function assertValidZrxAssetData() - public - pure - returns (bool) - { - bytes memory kovanZrxAssetData = abi.encodeWithSelector(ERC20_PROXY_ID, KOVAN_ZRX_ADDRESS); - require( - kovanZrxAssetData.equals(KOVAN_ZRX_ASSET_DATA), - "INVALID_KOVAN_ZRX_ASSET_DATA" - ); - - bytes memory mainetZrxAssetData = abi.encodeWithSelector(ERC20_PROXY_ID, MAINNET_ZRX_ADDRESS); - require( - mainetZrxAssetData.equals(MAINNET_ZRX_ASSET_DATA), - "INVALID_MAINNET_ZRX_ASSET_DATA" - ); - - return true; - } -} -// solhint-enable max-line-length
\ No newline at end of file diff --git a/contracts/core/contracts/test/TestLibBytes/TestLibBytes.sol b/contracts/core/contracts/test/TestLibBytes/TestLibBytes.sol deleted file mode 100644 index 00d861e61..000000000 --- a/contracts/core/contracts/test/TestLibBytes/TestLibBytes.sol +++ /dev/null @@ -1,269 +0,0 @@ -/* - - Copyright 2018 ZeroEx Intl. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - -*/ - -pragma solidity 0.4.24; - -import "../../utils/LibBytes/LibBytes.sol"; - - -contract TestLibBytes { - - using LibBytes for bytes; - - /// @dev Pops the last byte off of a byte array by modifying its length. - /// @param b Byte array that will be modified. - /// @return The byte that was popped off. - function publicPopLastByte(bytes memory b) - public - pure - returns (bytes memory, bytes1 result) - { - result = b.popLastByte(); - return (b, result); - } - - /// @dev Pops the last 20 bytes off of a byte array by modifying its length. - /// @param b Byte array that will be modified. - /// @return The 20 byte address that was popped off. - function publicPopLast20Bytes(bytes memory b) - public - pure - returns (bytes memory, address result) - { - result = b.popLast20Bytes(); - return (b, result); - } - - /// @dev Tests equality of two byte arrays. - /// @param lhs First byte array to compare. - /// @param rhs Second byte array to compare. - /// @return True if arrays are the same. False otherwise. - function publicEquals(bytes memory lhs, bytes memory rhs) - public - pure - returns (bool equal) - { - equal = lhs.equals(rhs); - return equal; - } - - function publicEqualsPop1(bytes memory lhs, bytes memory rhs) - public - pure - returns (bool equal) - { - lhs.popLastByte(); - rhs.popLastByte(); - equal = lhs.equals(rhs); - return equal; - } - - /// @dev Performs a deep copy of a byte array onto another byte array of greater than or equal length. - /// @param dest Byte array that will be overwritten with source bytes. - /// @param source Byte array to copy onto dest bytes. - function publicDeepCopyBytes( - bytes memory dest, - bytes memory source - ) - public - pure - returns (bytes memory) - { - LibBytes.deepCopyBytes(dest, source); - return dest; - } - - /// @dev Reads an address from a position in a byte array. - /// @param b Byte array containing an address. - /// @param index Index in byte array of address. - /// @return address from byte array. - function publicReadAddress( - bytes memory b, - uint256 index - ) - public - pure - returns (address result) - { - result = b.readAddress(index); - return result; - } - - /// @dev Writes an address into a specific position in a byte array. - /// @param b Byte array to insert address into. - /// @param index Index in byte array of address. - /// @param input Address to put into byte array. - function publicWriteAddress( - bytes memory b, - uint256 index, - address input - ) - public - pure - returns (bytes memory) - { - b.writeAddress(index, input); - return b; - } - - /// @dev Reads a bytes32 value from a position in a byte array. - /// @param b Byte array containing a bytes32 value. - /// @param index Index in byte array of bytes32 value. - /// @return bytes32 value from byte array. - function publicReadBytes32( - bytes memory b, - uint256 index - ) - public - pure - returns (bytes32 result) - { - result = b.readBytes32(index); - return result; - } - - /// @dev Writes a bytes32 into a specific position in a byte array. - /// @param b Byte array to insert <input> into. - /// @param index Index in byte array of <input>. - /// @param input bytes32 to put into byte array. - function publicWriteBytes32( - bytes memory b, - uint256 index, - bytes32 input - ) - public - pure - returns (bytes memory) - { - b.writeBytes32(index, input); - return b; - } - - /// @dev Reads a uint256 value from a position in a byte array. - /// @param b Byte array containing a uint256 value. - /// @param index Index in byte array of uint256 value. - /// @return uint256 value from byte array. - function publicReadUint256( - bytes memory b, - uint256 index - ) - public - pure - returns (uint256 result) - { - result = b.readUint256(index); - return result; - } - - /// @dev Writes a uint256 into a specific position in a byte array. - /// @param b Byte array to insert <input> into. - /// @param index Index in byte array of <input>. - /// @param input uint256 to put into byte array. - function publicWriteUint256( - bytes memory b, - uint256 index, - uint256 input - ) - public - pure - returns (bytes memory) - { - b.writeUint256(index, input); - return b; - } - - /// @dev Reads an unpadded bytes4 value from a position in a byte array. - /// @param b Byte array containing a bytes4 value. - /// @param index Index in byte array of bytes4 value. - /// @return bytes4 value from byte array. - function publicReadBytes4( - bytes memory b, - uint256 index - ) - public - pure - returns (bytes4 result) - { - result = b.readBytes4(index); - return result; - } - - /// @dev Reads nested bytes from a specific position. - /// @param b Byte array containing nested bytes. - /// @param index Index of nested bytes. - /// @return result Nested bytes. - function publicReadBytesWithLength( - bytes memory b, - uint256 index - ) - public - pure - returns (bytes memory result) - { - result = b.readBytesWithLength(index); - return result; - } - - /// @dev Inserts bytes at a specific position in a byte array. - /// @param b Byte array to insert <input> into. - /// @param index Index in byte array of <input>. - /// @param input bytes to insert. - /// @return b Updated input byte array - function publicWriteBytesWithLength( - bytes memory b, - uint256 index, - bytes memory input - ) - public - pure - returns (bytes memory) - { - b.writeBytesWithLength(index, input); - return b; - } - - /// @dev Copies a block of memory from one location to another. - /// @param mem Memory contents we want to apply memCopy to - /// @param dest Destination offset into <mem>. - /// @param source Source offset into <mem>. - /// @param length Length of bytes to copy from <source> to <dest> - /// @return mem Memory contents after calling memCopy. - function testMemcpy( - bytes mem, - uint256 dest, - uint256 source, - uint256 length - ) - public // not external, we need input in memory - pure - returns (bytes) - { - // Sanity check. Overflows are not checked. - require(source + length <= mem.length); - require(dest + length <= mem.length); - - // Get pointer to memory contents - uint256 offset = mem.contentAddress(); - - // Execute memCopy adjusted for memory array location - LibBytes.memCopy(offset + dest, offset + source, length); - - // Return modified memory contents - return mem; - } -} diff --git a/contracts/core/contracts/test/TestLibs/TestLibs.sol b/contracts/core/contracts/test/TestLibs/TestLibs.sol deleted file mode 100644 index a10f981fc..000000000 --- a/contracts/core/contracts/test/TestLibs/TestLibs.sol +++ /dev/null @@ -1,152 +0,0 @@ -/* - - Copyright 2018 ZeroEx Intl. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - -*/ - -pragma solidity 0.4.24; -pragma experimental ABIEncoderV2; - -import "../../protocol/Exchange/libs/LibMath.sol"; -import "../../protocol/Exchange/libs/LibOrder.sol"; -import "../../protocol/Exchange/libs/LibFillResults.sol"; -import "../../protocol/Exchange/libs/LibAbiEncoder.sol"; - - -contract TestLibs is - LibMath, - LibOrder, - LibFillResults, - LibAbiEncoder -{ - function publicAbiEncodeFillOrder( - Order memory order, - uint256 takerAssetFillAmount, - bytes memory signature - ) - public - pure - returns (bytes memory fillOrderCalldata) - { - fillOrderCalldata = abiEncodeFillOrder( - order, - takerAssetFillAmount, - signature - ); - return fillOrderCalldata; - } - - function publicGetPartialAmountFloor( - uint256 numerator, - uint256 denominator, - uint256 target - ) - public - pure - returns (uint256 partialAmount) - { - partialAmount = getPartialAmountFloor( - numerator, - denominator, - target - ); - return partialAmount; - } - - function publicGetPartialAmountCeil( - uint256 numerator, - uint256 denominator, - uint256 target - ) - public - pure - returns (uint256 partialAmount) - { - partialAmount = getPartialAmountCeil( - numerator, - denominator, - target - ); - return partialAmount; - } - - function publicIsRoundingErrorFloor( - uint256 numerator, - uint256 denominator, - uint256 target - ) - public - pure - returns (bool isError) - { - isError = isRoundingErrorFloor( - numerator, - denominator, - target - ); - return isError; - } - - function publicIsRoundingErrorCeil( - uint256 numerator, - uint256 denominator, - uint256 target - ) - public - pure - returns (bool isError) - { - isError = isRoundingErrorCeil( - numerator, - denominator, - target - ); - return isError; - } - - function publicGetOrderHash(Order memory order) - public - view - returns (bytes32 orderHash) - { - orderHash = getOrderHash(order); - return orderHash; - } - - function getOrderSchemaHash() - public - pure - returns (bytes32) - { - return EIP712_ORDER_SCHEMA_HASH; - } - - function getDomainSeparatorSchemaHash() - public - pure - returns (bytes32) - { - return EIP712_DOMAIN_SEPARATOR_SCHEMA_HASH; - } - - function publicAddFillResults(FillResults memory totalFillResults, FillResults memory singleFillResults) - public - pure - returns (FillResults memory) - { - addFillResults(totalFillResults, singleFillResults); - return totalFillResults; - } -} diff --git a/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/contracts/utils/LibBytes/LibBytes.sol b/contracts/core/contracts/utils/LibBytes/LibBytes.sol deleted file mode 100644 index 369f588ad..000000000 --- a/contracts/core/contracts/utils/LibBytes/LibBytes.sol +++ /dev/null @@ -1,567 +0,0 @@ -/* - - Copyright 2018 ZeroEx Intl. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - -*/ - -pragma solidity 0.4.24; - - -library LibBytes { - - using LibBytes for bytes; - - /// @dev Gets the memory address for a byte array. - /// @param input Byte array to lookup. - /// @return memoryAddress Memory address of byte array. This - /// points to the header of the byte array which contains - /// the length. - function rawAddress(bytes memory input) - internal - pure - returns (uint256 memoryAddress) - { - assembly { - memoryAddress := input - } - return memoryAddress; - } - - /// @dev Gets the memory address for the contents of a byte array. - /// @param input Byte array to lookup. - /// @return memoryAddress Memory address of the contents of the byte array. - function contentAddress(bytes memory input) - internal - pure - returns (uint256 memoryAddress) - { - assembly { - memoryAddress := add(input, 32) - } - return memoryAddress; - } - - /// @dev Copies `length` bytes from memory location `source` to `dest`. - /// @param dest memory address to copy bytes to. - /// @param source memory address to copy bytes from. - /// @param length number of bytes to copy. - function memCopy( - uint256 dest, - uint256 source, - uint256 length - ) - internal - pure - { - if (length < 32) { - // Handle a partial word by reading destination and masking - // off the bits we are interested in. - // This correctly handles overlap, zero lengths and source == dest - assembly { - let mask := sub(exp(256, sub(32, length)), 1) - let s := and(mload(source), not(mask)) - let d := and(mload(dest), mask) - mstore(dest, or(s, d)) - } - } else { - // Skip the O(length) loop when source == dest. - if (source == dest) { - return; - } - - // For large copies we copy whole words at a time. The final - // word is aligned to the end of the range (instead of after the - // previous) to handle partial words. So a copy will look like this: - // - // #### - // #### - // #### - // #### - // - // We handle overlap in the source and destination range by - // changing the copying direction. This prevents us from - // overwriting parts of source that we still need to copy. - // - // This correctly handles source == dest - // - if (source > dest) { - assembly { - // We subtract 32 from `sEnd` and `dEnd` because it - // is easier to compare with in the loop, and these - // are also the addresses we need for copying the - // last bytes. - length := sub(length, 32) - let sEnd := add(source, length) - let dEnd := add(dest, length) - - // Remember the last 32 bytes of source - // This needs to be done here and not after the loop - // because we may have overwritten the last bytes in - // source already due to overlap. - let last := mload(sEnd) - - // Copy whole words front to back - // Note: the first check is always true, - // this could have been a do-while loop. - // solhint-disable-next-line no-empty-blocks - for {} lt(source, sEnd) {} { - mstore(dest, mload(source)) - source := add(source, 32) - dest := add(dest, 32) - } - - // Write the last 32 bytes - mstore(dEnd, last) - } - } else { - assembly { - // We subtract 32 from `sEnd` and `dEnd` because those - // are the starting points when copying a word at the end. - length := sub(length, 32) - let sEnd := add(source, length) - let dEnd := add(dest, length) - - // Remember the first 32 bytes of source - // This needs to be done here and not after the loop - // because we may have overwritten the first bytes in - // source already due to overlap. - let first := mload(source) - - // Copy whole words back to front - // We use a signed comparisson here to allow dEnd to become - // negative (happens when source and dest < 32). Valid - // addresses in local memory will never be larger than - // 2**255, so they can be safely re-interpreted as signed. - // Note: the first check is always true, - // this could have been a do-while loop. - // solhint-disable-next-line no-empty-blocks - for {} slt(dest, dEnd) {} { - mstore(dEnd, mload(sEnd)) - sEnd := sub(sEnd, 32) - dEnd := sub(dEnd, 32) - } - - // Write the first 32 bytes - mstore(dest, first) - } - } - } - } - - /// @dev Returns a slices from a byte array. - /// @param b The byte array to take a slice from. - /// @param from The starting index for the slice (inclusive). - /// @param to The final index for the slice (exclusive). - /// @return result The slice containing bytes at indices [from, to) - function slice( - bytes memory b, - uint256 from, - uint256 to - ) - internal - pure - returns (bytes memory result) - { - require( - from <= to, - "FROM_LESS_THAN_TO_REQUIRED" - ); - require( - to < b.length, - "TO_LESS_THAN_LENGTH_REQUIRED" - ); - - // Create a new bytes structure and copy contents - result = new bytes(to - from); - memCopy( - result.contentAddress(), - b.contentAddress() + from, - result.length - ); - return result; - } - - /// @dev Returns a slice from a byte array without preserving the input. - /// @param b The byte array to take a slice from. Will be destroyed in the process. - /// @param from The starting index for the slice (inclusive). - /// @param to The final index for the slice (exclusive). - /// @return result The slice containing bytes at indices [from, to) - /// @dev When `from == 0`, the original array will match the slice. In other cases its state will be corrupted. - function sliceDestructive( - bytes memory b, - uint256 from, - uint256 to - ) - internal - pure - returns (bytes memory result) - { - require( - from <= to, - "FROM_LESS_THAN_TO_REQUIRED" - ); - require( - to < b.length, - "TO_LESS_THAN_LENGTH_REQUIRED" - ); - - // Create a new bytes structure around [from, to) in-place. - assembly { - result := add(b, from) - mstore(result, sub(to, from)) - } - return result; - } - - /// @dev Pops the last byte off of a byte array by modifying its length. - /// @param b Byte array that will be modified. - /// @return The byte that was popped off. - function popLastByte(bytes memory b) - internal - pure - returns (bytes1 result) - { - require( - b.length > 0, - "GREATER_THAN_ZERO_LENGTH_REQUIRED" - ); - - // Store last byte. - result = b[b.length - 1]; - - assembly { - // Decrement length of byte array. - let newLen := sub(mload(b), 1) - mstore(b, newLen) - } - return result; - } - - /// @dev Pops the last 20 bytes off of a byte array by modifying its length. - /// @param b Byte array that will be modified. - /// @return The 20 byte address that was popped off. - function popLast20Bytes(bytes memory b) - internal - pure - returns (address result) - { - require( - b.length >= 20, - "GREATER_OR_EQUAL_TO_20_LENGTH_REQUIRED" - ); - - // Store last 20 bytes. - result = readAddress(b, b.length - 20); - - assembly { - // Subtract 20 from byte array length. - let newLen := sub(mload(b), 20) - mstore(b, newLen) - } - return result; - } - - /// @dev Tests equality of two byte arrays. - /// @param lhs First byte array to compare. - /// @param rhs Second byte array to compare. - /// @return True if arrays are the same. False otherwise. - function equals( - bytes memory lhs, - bytes memory rhs - ) - internal - pure - returns (bool equal) - { - // Keccak gas cost is 30 + numWords * 6. This is a cheap way to compare. - // We early exit on unequal lengths, but keccak would also correctly - // handle this. - return lhs.length == rhs.length && keccak256(lhs) == keccak256(rhs); - } - - /// @dev Reads an address from a position in a byte array. - /// @param b Byte array containing an address. - /// @param index Index in byte array of address. - /// @return address from byte array. - function readAddress( - bytes memory b, - uint256 index - ) - internal - pure - returns (address result) - { - require( - b.length >= index + 20, // 20 is length of address - "GREATER_OR_EQUAL_TO_20_LENGTH_REQUIRED" - ); - - // Add offset to index: - // 1. Arrays are prefixed by 32-byte length parameter (add 32 to index) - // 2. Account for size difference between address length and 32-byte storage word (subtract 12 from index) - index += 20; - - // Read address from array memory - assembly { - // 1. Add index to address of bytes array - // 2. Load 32-byte word from memory - // 3. Apply 20-byte mask to obtain address - result := and(mload(add(b, index)), 0xffffffffffffffffffffffffffffffffffffffff) - } - return result; - } - - /// @dev Writes an address into a specific position in a byte array. - /// @param b Byte array to insert address into. - /// @param index Index in byte array of address. - /// @param input Address to put into byte array. - function writeAddress( - bytes memory b, - uint256 index, - address input - ) - internal - pure - { - require( - b.length >= index + 20, // 20 is length of address - "GREATER_OR_EQUAL_TO_20_LENGTH_REQUIRED" - ); - - // Add offset to index: - // 1. Arrays are prefixed by 32-byte length parameter (add 32 to index) - // 2. Account for size difference between address length and 32-byte storage word (subtract 12 from index) - index += 20; - - // Store address into array memory - assembly { - // The address occupies 20 bytes and mstore stores 32 bytes. - // First fetch the 32-byte word where we'll be storing the address, then - // apply a mask so we have only the bytes in the word that the address will not occupy. - // Then combine these bytes with the address and store the 32 bytes back to memory with mstore. - - // 1. Add index to address of bytes array - // 2. Load 32-byte word from memory - // 3. Apply 12-byte mask to obtain extra bytes occupying word of memory where we'll store the address - let neighbors := and( - mload(add(b, index)), - 0xffffffffffffffffffffffff0000000000000000000000000000000000000000 - ) - - // Make sure input address is clean. - // (Solidity does not guarantee this) - input := and(input, 0xffffffffffffffffffffffffffffffffffffffff) - - // Store the neighbors and address into memory - mstore(add(b, index), xor(input, neighbors)) - } - } - - /// @dev Reads a bytes32 value from a position in a byte array. - /// @param b Byte array containing a bytes32 value. - /// @param index Index in byte array of bytes32 value. - /// @return bytes32 value from byte array. - function readBytes32( - bytes memory b, - uint256 index - ) - internal - pure - returns (bytes32 result) - { - require( - b.length >= index + 32, - "GREATER_OR_EQUAL_TO_32_LENGTH_REQUIRED" - ); - - // Arrays are prefixed by a 256 bit length parameter - index += 32; - - // Read the bytes32 from array memory - assembly { - result := mload(add(b, index)) - } - return result; - } - - /// @dev Writes a bytes32 into a specific position in a byte array. - /// @param b Byte array to insert <input> into. - /// @param index Index in byte array of <input>. - /// @param input bytes32 to put into byte array. - function writeBytes32( - bytes memory b, - uint256 index, - bytes32 input - ) - internal - pure - { - require( - b.length >= index + 32, - "GREATER_OR_EQUAL_TO_32_LENGTH_REQUIRED" - ); - - // Arrays are prefixed by a 256 bit length parameter - index += 32; - - // Read the bytes32 from array memory - assembly { - mstore(add(b, index), input) - } - } - - /// @dev Reads a uint256 value from a position in a byte array. - /// @param b Byte array containing a uint256 value. - /// @param index Index in byte array of uint256 value. - /// @return uint256 value from byte array. - function readUint256( - bytes memory b, - uint256 index - ) - internal - pure - returns (uint256 result) - { - result = uint256(readBytes32(b, index)); - return result; - } - - /// @dev Writes a uint256 into a specific position in a byte array. - /// @param b Byte array to insert <input> into. - /// @param index Index in byte array of <input>. - /// @param input uint256 to put into byte array. - function writeUint256( - bytes memory b, - uint256 index, - uint256 input - ) - internal - pure - { - writeBytes32(b, index, bytes32(input)); - } - - /// @dev Reads an unpadded bytes4 value from a position in a byte array. - /// @param b Byte array containing a bytes4 value. - /// @param index Index in byte array of bytes4 value. - /// @return bytes4 value from byte array. - function readBytes4( - bytes memory b, - uint256 index - ) - internal - pure - returns (bytes4 result) - { - require( - b.length >= index + 4, - "GREATER_OR_EQUAL_TO_4_LENGTH_REQUIRED" - ); - - // Arrays are prefixed by a 32 byte length field - index += 32; - - // Read the bytes4 from array memory - assembly { - result := mload(add(b, index)) - // Solidity does not require us to clean the trailing bytes. - // We do it anyway - result := and(result, 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000) - } - return result; - } - - /// @dev Reads nested bytes from a specific position. - /// @dev NOTE: the returned value overlaps with the input value. - /// Both should be treated as immutable. - /// @param b Byte array containing nested bytes. - /// @param index Index of nested bytes. - /// @return result Nested bytes. - function readBytesWithLength( - bytes memory b, - uint256 index - ) - internal - pure - returns (bytes memory result) - { - // Read length of nested bytes - uint256 nestedBytesLength = readUint256(b, index); - index += 32; - - // Assert length of <b> is valid, given - // length of nested bytes - require( - b.length >= index + nestedBytesLength, - "GREATER_OR_EQUAL_TO_NESTED_BYTES_LENGTH_REQUIRED" - ); - - // Return a pointer to the byte array as it exists inside `b` - assembly { - result := add(b, index) - } - return result; - } - - /// @dev Inserts bytes at a specific position in a byte array. - /// @param b Byte array to insert <input> into. - /// @param index Index in byte array of <input>. - /// @param input bytes to insert. - function writeBytesWithLength( - bytes memory b, - uint256 index, - bytes memory input - ) - internal - pure - { - // Assert length of <b> is valid, given - // length of input - require( - b.length >= index + 32 + input.length, // 32 bytes to store length - "GREATER_OR_EQUAL_TO_NESTED_BYTES_LENGTH_REQUIRED" - ); - - // Copy <input> into <b> - memCopy( - b.contentAddress() + index, - input.rawAddress(), // includes length of <input> - input.length + 32 // +32 bytes to store <input> length - ); - } - - /// @dev Performs a deep copy of a byte array onto another byte array of greater than or equal length. - /// @param dest Byte array that will be overwritten with source bytes. - /// @param source Byte array to copy onto dest bytes. - function deepCopyBytes( - bytes memory dest, - bytes memory source - ) - internal - pure - { - uint256 sourceLen = source.length; - // Dest length must be >= source length, or some bytes would not be copied. - require( - dest.length >= sourceLen, - "GREATER_OR_EQUAL_TO_SOURCE_BYTES_LENGTH_REQUIRED" - ); - memCopy( - dest.contentAddress(), - source.contentAddress(), - sourceLen - ); - } -} diff --git a/contracts/core/contracts/utils/Ownable/IOwnable.sol b/contracts/core/contracts/utils/Ownable/IOwnable.sol deleted file mode 100644 index 5deb13497..000000000 --- a/contracts/core/contracts/utils/Ownable/IOwnable.sol +++ /dev/null @@ -1,8 +0,0 @@ -pragma solidity 0.4.24; - - -contract IOwnable { - - function transferOwnership(address newOwner) - public; -} diff --git a/contracts/core/contracts/utils/Ownable/Ownable.sol b/contracts/core/contracts/utils/Ownable/Ownable.sol deleted file mode 100644 index 0c830be68..000000000 --- a/contracts/core/contracts/utils/Ownable/Ownable.sol +++ /dev/null @@ -1,33 +0,0 @@ -pragma solidity 0.4.24; - -import "./IOwnable.sol"; - - -contract Ownable is - IOwnable -{ - address public owner; - - constructor () - public - { - owner = msg.sender; - } - - modifier onlyOwner() { - require( - msg.sender == owner, - "ONLY_CONTRACT_OWNER" - ); - _; - } - - function transferOwnership(address newOwner) - public - onlyOwner - { - if (newOwner != address(0)) { - owner = newOwner; - } - } -} diff --git a/contracts/core/contracts/utils/ReentrancyGuard/ReentrancyGuard.sol b/contracts/core/contracts/utils/ReentrancyGuard/ReentrancyGuard.sol deleted file mode 100644 index 9f98a7a16..000000000 --- a/contracts/core/contracts/utils/ReentrancyGuard/ReentrancyGuard.sol +++ /dev/null @@ -1,45 +0,0 @@ -/* - - Copyright 2018 ZeroEx Intl. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - -*/ - -pragma solidity 0.4.24; - - -contract ReentrancyGuard { - - // Locked state of mutex - bool private locked = false; - - /// @dev Functions with this modifer cannot be reentered. The mutex will be locked - /// before function execution and unlocked after. - modifier nonReentrant() { - // Ensure mutex is unlocked - require( - !locked, - "REENTRANCY_ILLEGAL" - ); - - // Lock mutex before function call - locked = true; - - // Perform function call - _; - - // Unlock mutex after function call - locked = false; - } -} diff --git a/contracts/core/contracts/utils/SafeMath/SafeMath.sol b/contracts/core/contracts/utils/SafeMath/SafeMath.sol deleted file mode 100644 index 2855edb9d..000000000 --- a/contracts/core/contracts/utils/SafeMath/SafeMath.sol +++ /dev/null @@ -1,87 +0,0 @@ -pragma solidity 0.4.24; - - -contract SafeMath { - - function safeMul(uint256 a, uint256 b) - internal - pure - returns (uint256) - { - if (a == 0) { - return 0; - } - uint256 c = a * b; - require( - c / a == b, - "UINT256_OVERFLOW" - ); - return c; - } - - function safeDiv(uint256 a, uint256 b) - internal - pure - returns (uint256) - { - uint256 c = a / b; - return c; - } - - function safeSub(uint256 a, uint256 b) - internal - pure - returns (uint256) - { - require( - b <= a, - "UINT256_UNDERFLOW" - ); - return a - b; - } - - function safeAdd(uint256 a, uint256 b) - internal - pure - returns (uint256) - { - uint256 c = a + b; - require( - c >= a, - "UINT256_OVERFLOW" - ); - return c; - } - - function max64(uint64 a, uint64 b) - internal - pure - returns (uint256) - { - return a >= b ? a : b; - } - - function min64(uint64 a, uint64 b) - internal - pure - returns (uint256) - { - return a < b ? a : b; - } - - function max256(uint256 a, uint256 b) - internal - pure - returns (uint256) - { - return a >= b ? a : b; - } - - function min256(uint256 a, uint256 b) - internal - pure - returns (uint256) - { - return a < b ? a : b; - } -} diff --git a/contracts/core/package.json b/contracts/core/package.json index 457625791..43fa9370e 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|DutchAuction|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|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,9 @@ "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/contracts-libs": "^1.0.0", "@0x/types": "^1.3.0", "@0x/typescript-typings": "^3.0.4", "@0x/utils": "^2.0.6", @@ -82,10 +84,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 8a8c5f4d4..d578c36fe 100644 --- a/contracts/core/src/artifacts/index.ts +++ b/contracts/core/src/artifacts/index.ts @@ -21,16 +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'; import * as Validator from '../../generated-artifacts/Validator.json'; @@ -61,16 +56,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, Validator: Validator as ContractArtifact, diff --git a/contracts/core/src/wrappers/index.ts b/contracts/core/src/wrappers/index.ts index e9e3f4e79..ed9d8ef47 100644 --- a/contracts/core/src/wrappers/index.ts +++ b/contracts/core/src/wrappers/index.ts @@ -16,16 +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'; export * from '../../generated-wrappers/validator'; 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 deleted file mode 100644 index 503ef0e0f..000000000 --- a/contracts/core/test/exchange/libs.ts +++ /dev/null @@ -1,137 +0,0 @@ -import { BlockchainLifecycle } from '@0x/dev-utils'; -import { assetDataUtils, orderHashUtils } from '@0x/order-utils'; -import { SignedOrder } from '@0x/types'; -import { BigNumber } from '@0x/utils'; -import * as chai from 'chai'; - -import { TestConstantsContract } from '../../generated-wrappers/test_constants'; -import { TestLibsContract } from '../../generated-wrappers/test_libs'; -import { artifacts } from '../../src/artifacts'; -import { addressUtils } from '../utils/address_utils'; -import { chaiSetup } from '../utils/chai_setup'; -import { constants } from '../utils/constants'; -import { OrderFactory } from '../utils/order_factory'; -import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper'; - -chaiSetup.configure(); -const expect = chai.expect; - -const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); - -describe('Exchange libs', () => { - let signedOrder: SignedOrder; - let orderFactory: OrderFactory; - let libs: TestLibsContract; - let testConstants: TestConstantsContract; - - before(async () => { - await blockchainLifecycle.startAsync(); - }); - after(async () => { - await blockchainLifecycle.revertAsync(); - }); - before(async () => { - const accounts = await web3Wrapper.getAvailableAddressesAsync(); - const makerAddress = accounts[0]; - libs = await TestLibsContract.deployFrom0xArtifactAsync(artifacts.TestLibs, provider, txDefaults); - testConstants = await TestConstantsContract.deployFrom0xArtifactAsync( - artifacts.TestConstants, - provider, - txDefaults, - ); - - const defaultOrderParams = { - ...constants.STATIC_ORDER_PARAMS, - exchangeAddress: libs.address, - makerAddress, - feeRecipientAddress: addressUtils.generatePseudoRandomAddress(), - makerAssetData: assetDataUtils.encodeERC20AssetData(addressUtils.generatePseudoRandomAddress()), - takerAssetData: assetDataUtils.encodeERC20AssetData(addressUtils.generatePseudoRandomAddress()), - }; - const privateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddress)]; - orderFactory = new OrderFactory(privateKey, defaultOrderParams); - }); - - beforeEach(async () => { - await blockchainLifecycle.startAsync(); - }); - afterEach(async () => { - await blockchainLifecycle.revertAsync(); - }); - - describe('LibConstants', () => { - describe('ZRX_ASSET_DATA', () => { - it('should have the correct ZRX_ASSET_DATA', async () => { - const isValid = await testConstants.assertValidZrxAssetData.callAsync(); - expect(isValid).to.be.equal(true); - }); - }); - }); - // Note(albrow): These tests are designed to be supplemental to the - // combinatorial tests in test/exchange/internal. They test specific edge - // cases that are not covered by the combinatorial tests. - describe('LibMath', () => { - describe('isRoundingError', () => { - it('should return true if there is a rounding error of 0.1%', async () => { - const numerator = new BigNumber(20); - const denominator = new BigNumber(999); - const target = new BigNumber(50); - // rounding error = ((20*50/999) - floor(20*50/999)) / (20*50/999) = 0.1% - const isRoundingError = await libs.publicIsRoundingErrorFloor.callAsync(numerator, denominator, target); - expect(isRoundingError).to.be.true(); - }); - it('should return false if there is a rounding of 0.09%', async () => { - const numerator = new BigNumber(20); - const denominator = new BigNumber(9991); - const target = new BigNumber(500); - // rounding error = ((20*500/9991) - floor(20*500/9991)) / (20*500/9991) = 0.09% - const isRoundingError = await libs.publicIsRoundingErrorFloor.callAsync(numerator, denominator, target); - expect(isRoundingError).to.be.false(); - }); - it('should return true if there is a rounding error of 0.11%', async () => { - const numerator = new BigNumber(20); - const denominator = new BigNumber(9989); - const target = new BigNumber(500); - // rounding error = ((20*500/9989) - floor(20*500/9989)) / (20*500/9989) = 0.011% - const isRoundingError = await libs.publicIsRoundingErrorFloor.callAsync(numerator, denominator, target); - expect(isRoundingError).to.be.true(); - }); - }); - describe('isRoundingErrorCeil', () => { - it('should return true if there is a rounding error of 0.1%', async () => { - const numerator = new BigNumber(20); - const denominator = new BigNumber(1001); - const target = new BigNumber(50); - // rounding error = (ceil(20*50/1001) - (20*50/1001)) / (20*50/1001) = 0.1% - const isRoundingError = await libs.publicIsRoundingErrorCeil.callAsync(numerator, denominator, target); - expect(isRoundingError).to.be.true(); - }); - it('should return false if there is a rounding of 0.09%', async () => { - const numerator = new BigNumber(20); - const denominator = new BigNumber(10009); - const target = new BigNumber(500); - // rounding error = (ceil(20*500/10009) - (20*500/10009)) / (20*500/10009) = 0.09% - const isRoundingError = await libs.publicIsRoundingErrorCeil.callAsync(numerator, denominator, target); - expect(isRoundingError).to.be.false(); - }); - it('should return true if there is a rounding error of 0.11%', async () => { - const numerator = new BigNumber(20); - const denominator = new BigNumber(10011); - const target = new BigNumber(500); - // rounding error = (ceil(20*500/10011) - (20*500/10011)) / (20*500/10011) = 0.11% - const isRoundingError = await libs.publicIsRoundingErrorCeil.callAsync(numerator, denominator, target); - expect(isRoundingError).to.be.true(); - }); - }); - }); - - describe('LibOrder', () => { - describe('getOrderHash', () => { - it('should output the correct orderHash', async () => { - signedOrder = await orderFactory.newSignedOrderAsync(); - const orderHashHex = await libs.publicGetOrderHash.callAsync(signedOrder); - expect(orderHashUtils.getOrderHashHex(signedOrder)).to.be.equal(orderHashHex); - }); - }); - }); -}); diff --git a/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 index c133d8c60..54e6092d7 100644 --- a/contracts/core/test/extensions/dutch_auction.ts +++ b/contracts/core/test/extensions/dutch_auction.ts @@ -1,3 +1,15 @@ +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'; @@ -14,16 +26,9 @@ 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 { expectTransactionFailedAsync } from '../utils/assertions'; -import { getLatestBlockTimestampAsync } 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 { ContractName, ERC20BalancesByOwner } from '../utils/types'; -import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper'; chaiSetup.configure(); const expect = chai.expect; @@ -57,16 +62,6 @@ describe(ContractName.DutchAuction, () => { 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([ @@ -271,34 +266,6 @@ describe(ContractName.DutchAuction, () => { 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), @@ -370,7 +337,6 @@ describe(ContractName.DutchAuction, () => { ); }); it('cannot be filled for less than the current price', async () => { - await increaseTimeAsync(); buyOrder = await buyerOrderFactory.newSignedOrderAsync({ makerAssetAmount: sellOrder.takerAssetAmount, }); 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/libraries/lib_bytes.ts b/contracts/core/test/libraries/lib_bytes.ts deleted file mode 100644 index b1a389f00..000000000 --- a/contracts/core/test/libraries/lib_bytes.ts +++ /dev/null @@ -1,871 +0,0 @@ -import { BlockchainLifecycle } from '@0x/dev-utils'; -import { generatePseudoRandomSalt } from '@0x/order-utils'; -import { RevertReason } from '@0x/types'; -import { BigNumber } from '@0x/utils'; -import BN = require('bn.js'); -import * as chai from 'chai'; -import ethUtil = require('ethereumjs-util'); -import * as _ from 'lodash'; - -import { TestLibBytesContract } from '../../generated-wrappers/test_lib_bytes'; -import { artifacts } from '../../src/artifacts'; -import { expectContractCallFailedAsync } from '../utils/assertions'; -import { chaiSetup } from '../utils/chai_setup'; -import { constants } from '../utils/constants'; -import { typeEncodingUtils } from '../utils/type_encoding_utils'; -import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper'; - -chaiSetup.configure(); -const expect = chai.expect; -const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); - -// BUG: Ideally we would use Buffer.from(memory).toString('hex') -// https://github.com/Microsoft/TypeScript/issues/23155 -const toHex = (buf: Uint8Array): string => buf.reduce((a, v) => a + ('00' + v.toString(16)).slice(-2), '0x'); - -const fromHex = (str: string): Uint8Array => Uint8Array.from(Buffer.from(str.slice(2), 'hex')); - -describe('LibBytes', () => { - let libBytes: TestLibBytesContract; - const byteArrayShorterThan32Bytes = '0x012345'; - const byteArrayShorterThan20Bytes = byteArrayShorterThan32Bytes; - const byteArrayLongerThan32Bytes = - '0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef'; - const byteArrayLongerThan32BytesFirstBytesSwapped = - '0x2301456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef'; - const byteArrayLongerThan32BytesLastBytesSwapped = - '0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abefcd'; - let testAddress: string; - let testAddressB: string; - const testBytes32 = '0x102030405060708090a0b0c0d0e0f0102030405060708090a0b0c0d0e0f01020'; - const testBytes32B = '0x534877abd8443578526845cdfef020047528759477fedef87346527659aced32'; - const testUint256 = new BigNumber(testBytes32, 16); - const testUint256B = new BigNumber(testBytes32B, 16); - const testBytes4 = '0xabcdef12'; - const testByte = '0xab'; - let shortData: string; - let shortTestBytes: string; - let shortTestBytesAsBuffer: Buffer; - let wordOfData: string; - let wordOfTestBytes: string; - let wordOfTestBytesAsBuffer: Buffer; - let longData: string; - let longTestBytes: string; - let longTestBytesAsBuffer: Buffer; - - before(async () => { - await blockchainLifecycle.startAsync(); - }); - after(async () => { - await blockchainLifecycle.revertAsync(); - }); - before(async () => { - // Setup accounts & addresses - const accounts = await web3Wrapper.getAvailableAddressesAsync(); - testAddress = accounts[1]; - testAddressB = accounts[2]; - // Deploy LibBytes - libBytes = await TestLibBytesContract.deployFrom0xArtifactAsync(artifacts.TestLibBytes, provider, txDefaults); - // Verify lengths of test data - const byteArrayShorterThan32BytesLength = ethUtil.toBuffer(byteArrayShorterThan32Bytes).byteLength; - expect(byteArrayShorterThan32BytesLength).to.be.lessThan(32); - const byteArrayLongerThan32BytesLength = ethUtil.toBuffer(byteArrayLongerThan32Bytes).byteLength; - expect(byteArrayLongerThan32BytesLength).to.be.greaterThan(32); - const testBytes32Length = ethUtil.toBuffer(testBytes32).byteLength; - expect(testBytes32Length).to.be.equal(32); - // Create short test bytes - shortData = '0xffffaa'; - const encodedShortData = ethUtil.toBuffer(shortData); - const shortDataLength = new BigNumber(encodedShortData.byteLength); - const encodedShortDataLength = typeEncodingUtils.encodeUint256(shortDataLength); - shortTestBytesAsBuffer = Buffer.concat([encodedShortDataLength, encodedShortData]); - shortTestBytes = ethUtil.bufferToHex(shortTestBytesAsBuffer); - // Create test bytes one word in length - wordOfData = ethUtil.bufferToHex(typeEncodingUtils.encodeUint256(generatePseudoRandomSalt())); - const encodedWordOfData = ethUtil.toBuffer(wordOfData); - const wordOfDataLength = new BigNumber(encodedWordOfData.byteLength); - const encodedWordOfDataLength = typeEncodingUtils.encodeUint256(wordOfDataLength); - wordOfTestBytesAsBuffer = Buffer.concat([encodedWordOfDataLength, encodedWordOfData]); - wordOfTestBytes = ethUtil.bufferToHex(wordOfTestBytesAsBuffer); - // Create long test bytes (combines short test bytes with word of test bytes) - longData = ethUtil.bufferToHex(Buffer.concat([encodedShortData, encodedWordOfData])); - const longDataLength = new BigNumber(encodedShortData.byteLength + encodedWordOfData.byteLength); - const encodedLongDataLength = typeEncodingUtils.encodeUint256(longDataLength); - longTestBytesAsBuffer = Buffer.concat([encodedLongDataLength, encodedShortData, encodedWordOfData]); - longTestBytes = ethUtil.bufferToHex(longTestBytesAsBuffer); - }); - beforeEach(async () => { - await blockchainLifecycle.startAsync(); - }); - afterEach(async () => { - await blockchainLifecycle.revertAsync(); - }); - - describe('popLastByte', () => { - it('should revert if length is 0', async () => { - return expectContractCallFailedAsync( - libBytes.publicPopLastByte.callAsync(constants.NULL_BYTES), - RevertReason.LibBytesGreaterThanZeroLengthRequired, - ); - }); - it('should pop the last byte from the input and return it when array holds more than 1 byte', async () => { - const [newBytes, poppedByte] = await libBytes.publicPopLastByte.callAsync(byteArrayLongerThan32Bytes); - const expectedNewBytes = byteArrayLongerThan32Bytes.slice(0, -2); - const expectedPoppedByte = `0x${byteArrayLongerThan32Bytes.slice(-2)}`; - expect(newBytes).to.equal(expectedNewBytes); - expect(poppedByte).to.equal(expectedPoppedByte); - }); - it('should pop the last byte from the input and return it when array is exactly 1 byte', async () => { - const [newBytes, poppedByte] = await libBytes.publicPopLastByte.callAsync(testByte); - const expectedNewBytes = '0x'; - expect(newBytes).to.equal(expectedNewBytes); - return expect(poppedByte).to.be.equal(testByte); - }); - }); - - describe('popLast20Bytes', () => { - it('should revert if length is less than 20', async () => { - return expectContractCallFailedAsync( - libBytes.publicPopLast20Bytes.callAsync(byteArrayShorterThan20Bytes), - RevertReason.LibBytesGreaterOrEqualTo20LengthRequired, - ); - }); - it('should pop the last 20 bytes from the input and return it when array holds more than 20 bytes', async () => { - const [newBytes, poppedAddress] = await libBytes.publicPopLast20Bytes.callAsync(byteArrayLongerThan32Bytes); - const expectedNewBytes = byteArrayLongerThan32Bytes.slice(0, -40); - const expectedPoppedAddress = `0x${byteArrayLongerThan32Bytes.slice(-40)}`; - expect(newBytes).to.equal(expectedNewBytes); - expect(poppedAddress).to.equal(expectedPoppedAddress); - }); - it('should pop the last 20 bytes from the input and return it when array is exactly 20 bytes', async () => { - const [newBytes, poppedAddress] = await libBytes.publicPopLast20Bytes.callAsync(testAddress); - const expectedNewBytes = '0x'; - const expectedPoppedAddress = testAddress; - expect(newBytes).to.equal(expectedNewBytes); - expect(poppedAddress).to.equal(expectedPoppedAddress); - }); - }); - - describe('equals', () => { - it('should return true if byte arrays are equal (both arrays < 32 bytes)', async () => { - const isEqual = await libBytes.publicEquals.callAsync( - byteArrayShorterThan32Bytes, - byteArrayShorterThan32Bytes, - ); - return expect(isEqual).to.be.true(); - }); - it('should return true if byte arrays are equal (both arrays > 32 bytes)', async () => { - const isEqual = await libBytes.publicEquals.callAsync( - byteArrayLongerThan32Bytes, - byteArrayLongerThan32Bytes, - ); - return expect(isEqual).to.be.true(); - }); - it('should return false if byte arrays are not equal (first array < 32 bytes, second array > 32 bytes)', async () => { - const isEqual = await libBytes.publicEquals.callAsync( - byteArrayShorterThan32Bytes, - byteArrayLongerThan32Bytes, - ); - return expect(isEqual).to.be.false(); - }); - it('should return false if byte arrays are not equal (first array > 32 bytes, second array < 32 bytes)', async () => { - const isEqual = await libBytes.publicEquals.callAsync( - byteArrayLongerThan32Bytes, - byteArrayShorterThan32Bytes, - ); - return expect(isEqual).to.be.false(); - }); - it('should return false if byte arrays are not equal (same length, but a byte in first word differs)', async () => { - const isEqual = await libBytes.publicEquals.callAsync( - byteArrayLongerThan32BytesFirstBytesSwapped, - byteArrayLongerThan32Bytes, - ); - return expect(isEqual).to.be.false(); - }); - it('should return false if byte arrays are not equal (same length, but a byte in last word differs)', async () => { - const isEqual = await libBytes.publicEquals.callAsync( - byteArrayLongerThan32BytesLastBytesSwapped, - byteArrayLongerThan32Bytes, - ); - return expect(isEqual).to.be.false(); - }); - - describe('should ignore trailing data', () => { - it('should return true when both < 32 bytes', async () => { - const isEqual = await libBytes.publicEqualsPop1.callAsync('0x0102', '0x0103'); - return expect(isEqual).to.be.true(); - }); - }); - }); - - describe('deepCopyBytes', () => { - it('should revert if dest is shorter than source', async () => { - return expectContractCallFailedAsync( - libBytes.publicDeepCopyBytes.callAsync(byteArrayShorterThan32Bytes, byteArrayLongerThan32Bytes), - RevertReason.LibBytesGreaterOrEqualToSourceBytesLengthRequired, - ); - }); - it('should overwrite dest with source if source and dest have equal length', async () => { - const zeroedByteArrayLongerThan32Bytes = `0x${_.repeat('0', byteArrayLongerThan32Bytes.length - 2)}`; - const zeroedBytesAfterCopy = await libBytes.publicDeepCopyBytes.callAsync( - zeroedByteArrayLongerThan32Bytes, - byteArrayLongerThan32Bytes, - ); - return expect(zeroedBytesAfterCopy).to.be.equal(byteArrayLongerThan32Bytes); - }); - it('should overwrite the leftmost len(source) bytes of dest if dest is larger than source', async () => { - const zeroedByteArrayLongerThan32Bytes = `0x${_.repeat('0', byteArrayLongerThan32Bytes.length * 2)}`; - const zeroedBytesAfterCopy = await libBytes.publicDeepCopyBytes.callAsync( - zeroedByteArrayLongerThan32Bytes, - byteArrayLongerThan32Bytes, - ); - const copiedBytes = zeroedBytesAfterCopy.slice(0, byteArrayLongerThan32Bytes.length); - return expect(copiedBytes).to.be.equal(byteArrayLongerThan32Bytes); - }); - it('should not overwrite the rightmost bytes of dest if dest is larger than source', async () => { - const zeroedByteArrayLongerThan32Bytes = `0x${_.repeat('0', byteArrayLongerThan32Bytes.length * 2)}`; - const zeroedBytesAfterCopy = await libBytes.publicDeepCopyBytes.callAsync( - zeroedByteArrayLongerThan32Bytes, - byteArrayLongerThan32Bytes, - ); - const expectedNotCopiedBytes = zeroedByteArrayLongerThan32Bytes.slice(byteArrayLongerThan32Bytes.length); - const notCopiedBytes = zeroedBytesAfterCopy.slice(byteArrayLongerThan32Bytes.length); - return expect(notCopiedBytes).to.be.equal(expectedNotCopiedBytes); - }); - }); - - describe('readAddress', () => { - it('should successfully read address when the address takes up the whole array', async () => { - const byteArray = ethUtil.addHexPrefix(testAddress); - const testAddressOffset = new BigNumber(0); - const address = await libBytes.publicReadAddress.callAsync(byteArray, testAddressOffset); - return expect(address).to.be.equal(testAddress); - }); - it('should successfully read address when it is offset in the array', async () => { - const addressByteArrayBuffer = ethUtil.toBuffer(testAddress); - const prefixByteArrayBuffer = ethUtil.toBuffer('0xabcdef'); - const combinedByteArrayBuffer = Buffer.concat([prefixByteArrayBuffer, addressByteArrayBuffer]); - const combinedByteArray = ethUtil.bufferToHex(combinedByteArrayBuffer); - const testAddressOffset = new BigNumber(prefixByteArrayBuffer.byteLength); - const address = await libBytes.publicReadAddress.callAsync(combinedByteArray, testAddressOffset); - return expect(address).to.be.equal(testAddress); - }); - it('should fail if the byte array is too short to hold an address', async () => { - const shortByteArray = '0xabcdef'; - const offset = new BigNumber(0); - return expectContractCallFailedAsync( - libBytes.publicReadAddress.callAsync(shortByteArray, offset), - RevertReason.LibBytesGreaterOrEqualTo20LengthRequired, - ); - }); - it('should fail if the length between the offset and end of the byte array is too short to hold an address', async () => { - const byteArray = testAddress; - const badOffset = new BigNumber(ethUtil.toBuffer(byteArray).byteLength); - return expectContractCallFailedAsync( - libBytes.publicReadAddress.callAsync(byteArray, badOffset), - RevertReason.LibBytesGreaterOrEqualTo20LengthRequired, - ); - }); - }); - - describe('writeAddress', () => { - it('should successfully write address when the address takes up the whole array', async () => { - const byteArray = testAddress; - const testAddressOffset = new BigNumber(0); - const newByteArray = await libBytes.publicWriteAddress.callAsync( - byteArray, - testAddressOffset, - testAddressB, - ); - return expect(newByteArray).to.be.equal(testAddressB); - }); - it('should successfully write address when it is offset in the array', async () => { - const addressByteArrayBuffer = ethUtil.toBuffer(testAddress); - const prefixByteArrayBuffer = ethUtil.toBuffer('0xabcdef'); - const combinedByteArrayBuffer = Buffer.concat([prefixByteArrayBuffer, addressByteArrayBuffer]); - const combinedByteArray = ethUtil.bufferToHex(combinedByteArrayBuffer); - const testAddressOffset = new BigNumber(prefixByteArrayBuffer.byteLength); - const newByteArray = await libBytes.publicWriteAddress.callAsync( - combinedByteArray, - testAddressOffset, - testAddressB, - ); - const newByteArrayBuffer = ethUtil.toBuffer(newByteArray); - const addressFromOffsetBuffer = newByteArrayBuffer.slice(prefixByteArrayBuffer.byteLength); - const addressFromOffset = ethUtil.addHexPrefix(ethUtil.bufferToHex(addressFromOffsetBuffer)); - return expect(addressFromOffset).to.be.equal(testAddressB); - }); - it('should fail if the byte array is too short to hold an address', async () => { - const offset = new BigNumber(0); - return expectContractCallFailedAsync( - libBytes.publicWriteAddress.callAsync(byteArrayShorterThan20Bytes, offset, testAddress), - RevertReason.LibBytesGreaterOrEqualTo20LengthRequired, - ); - }); - it('should fail if the length between the offset and end of the byte array is too short to hold an address', async () => { - const byteArray = byteArrayLongerThan32Bytes; - const badOffset = new BigNumber(ethUtil.toBuffer(byteArray).byteLength); - return expectContractCallFailedAsync( - libBytes.publicWriteAddress.callAsync(byteArray, badOffset, testAddress), - RevertReason.LibBytesGreaterOrEqualTo20LengthRequired, - ); - }); - }); - - describe('readBytes32', () => { - it('should successfully read bytes32 when the bytes32 takes up the whole array', async () => { - const testBytes32Offset = new BigNumber(0); - const bytes32 = await libBytes.publicReadBytes32.callAsync(testBytes32, testBytes32Offset); - return expect(bytes32).to.be.equal(testBytes32); - }); - it('should successfully read bytes32 when it is offset in the array', async () => { - const bytes32ByteArrayBuffer = ethUtil.toBuffer(testBytes32); - const prefixByteArrayBuffer = ethUtil.toBuffer('0xabcdef'); - const combinedByteArrayBuffer = Buffer.concat([prefixByteArrayBuffer, bytes32ByteArrayBuffer]); - const combinedByteArray = ethUtil.bufferToHex(combinedByteArrayBuffer); - const testBytes32Offset = new BigNumber(prefixByteArrayBuffer.byteLength); - const bytes32 = await libBytes.publicReadBytes32.callAsync(combinedByteArray, testBytes32Offset); - return expect(bytes32).to.be.equal(testBytes32); - }); - it('should fail if the byte array is too short to hold a bytes32', async () => { - const offset = new BigNumber(0); - return expectContractCallFailedAsync( - libBytes.publicReadBytes32.callAsync(byteArrayShorterThan32Bytes, offset), - RevertReason.LibBytesGreaterOrEqualTo32LengthRequired, - ); - }); - it('should fail if the length between the offset and end of the byte array is too short to hold a bytes32', async () => { - const badOffset = new BigNumber(ethUtil.toBuffer(testBytes32).byteLength); - return expectContractCallFailedAsync( - libBytes.publicReadBytes32.callAsync(testBytes32, badOffset), - RevertReason.LibBytesGreaterOrEqualTo32LengthRequired, - ); - }); - }); - - describe('writeBytes32', () => { - it('should successfully write bytes32 when the address takes up the whole array', async () => { - const byteArray = testBytes32; - const testBytes32Offset = new BigNumber(0); - const newByteArray = await libBytes.publicWriteBytes32.callAsync( - byteArray, - testBytes32Offset, - testBytes32B, - ); - return expect(newByteArray).to.be.equal(testBytes32B); - }); - it('should successfully write bytes32 when it is offset in the array', async () => { - const bytes32ByteArrayBuffer = ethUtil.toBuffer(testBytes32); - const prefixByteArrayBuffer = ethUtil.toBuffer('0xabcdef'); - const combinedByteArrayBuffer = Buffer.concat([prefixByteArrayBuffer, bytes32ByteArrayBuffer]); - const combinedByteArray = ethUtil.bufferToHex(combinedByteArrayBuffer); - const testBytes32Offset = new BigNumber(prefixByteArrayBuffer.byteLength); - const newByteArray = await libBytes.publicWriteBytes32.callAsync( - combinedByteArray, - testBytes32Offset, - testBytes32B, - ); - const newByteArrayBuffer = ethUtil.toBuffer(newByteArray); - const bytes32FromOffsetBuffer = newByteArrayBuffer.slice(prefixByteArrayBuffer.byteLength); - const bytes32FromOffset = ethUtil.addHexPrefix(ethUtil.bufferToHex(bytes32FromOffsetBuffer)); - return expect(bytes32FromOffset).to.be.equal(testBytes32B); - }); - it('should fail if the byte array is too short to hold a bytes32', async () => { - const offset = new BigNumber(0); - return expectContractCallFailedAsync( - libBytes.publicWriteBytes32.callAsync(byteArrayShorterThan32Bytes, offset, testBytes32), - RevertReason.LibBytesGreaterOrEqualTo32LengthRequired, - ); - }); - it('should fail if the length between the offset and end of the byte array is too short to hold a bytes32', async () => { - const byteArray = byteArrayLongerThan32Bytes; - const badOffset = new BigNumber(ethUtil.toBuffer(byteArray).byteLength); - return expectContractCallFailedAsync( - libBytes.publicWriteBytes32.callAsync(byteArray, badOffset, testBytes32), - RevertReason.LibBytesGreaterOrEqualTo32LengthRequired, - ); - }); - }); - - describe('readUint256', () => { - it('should successfully read uint256 when the uint256 takes up the whole array', async () => { - const formattedTestUint256 = new BN(testUint256.toString(10)); - const testUint256AsBuffer = ethUtil.toBuffer(formattedTestUint256); - const byteArray = ethUtil.bufferToHex(testUint256AsBuffer); - const testUint256Offset = new BigNumber(0); - const uint256 = await libBytes.publicReadUint256.callAsync(byteArray, testUint256Offset); - return expect(uint256).to.bignumber.equal(testUint256); - }); - it('should successfully read uint256 when it is offset in the array', async () => { - const prefixByteArrayBuffer = ethUtil.toBuffer('0xabcdef'); - const formattedTestUint256 = new BN(testUint256.toString(10)); - const testUint256AsBuffer = ethUtil.toBuffer(formattedTestUint256); - const combinedByteArrayBuffer = Buffer.concat([prefixByteArrayBuffer, testUint256AsBuffer]); - const combinedByteArray = ethUtil.bufferToHex(combinedByteArrayBuffer); - const testUint256Offset = new BigNumber(prefixByteArrayBuffer.byteLength); - const uint256 = await libBytes.publicReadUint256.callAsync(combinedByteArray, testUint256Offset); - return expect(uint256).to.bignumber.equal(testUint256); - }); - it('should fail if the byte array is too short to hold a uint256', async () => { - const offset = new BigNumber(0); - return expectContractCallFailedAsync( - libBytes.publicReadUint256.callAsync(byteArrayShorterThan32Bytes, offset), - RevertReason.LibBytesGreaterOrEqualTo32LengthRequired, - ); - }); - it('should fail if the length between the offset and end of the byte array is too short to hold a uint256', async () => { - const formattedTestUint256 = new BN(testUint256.toString(10)); - const testUint256AsBuffer = ethUtil.toBuffer(formattedTestUint256); - const byteArray = ethUtil.bufferToHex(testUint256AsBuffer); - const badOffset = new BigNumber(testUint256AsBuffer.byteLength); - return expectContractCallFailedAsync( - libBytes.publicReadUint256.callAsync(byteArray, badOffset), - RevertReason.LibBytesGreaterOrEqualTo32LengthRequired, - ); - }); - }); - - describe('writeUint256', () => { - it('should successfully write uint256 when the address takes up the whole array', async () => { - const byteArray = testBytes32; - const testUint256Offset = new BigNumber(0); - const newByteArray = await libBytes.publicWriteUint256.callAsync( - byteArray, - testUint256Offset, - testUint256B, - ); - const newByteArrayAsUint256 = new BigNumber(newByteArray, 16); - return expect(newByteArrayAsUint256).to.be.bignumber.equal(testUint256B); - }); - it('should successfully write uint256 when it is offset in the array', async () => { - const bytes32ByteArrayBuffer = ethUtil.toBuffer(testBytes32); - const prefixByteArrayBuffer = ethUtil.toBuffer('0xabcdef'); - const combinedByteArrayBuffer = Buffer.concat([prefixByteArrayBuffer, bytes32ByteArrayBuffer]); - const combinedByteArray = ethUtil.bufferToHex(combinedByteArrayBuffer); - const testUint256Offset = new BigNumber(prefixByteArrayBuffer.byteLength); - const newByteArray = await libBytes.publicWriteUint256.callAsync( - combinedByteArray, - testUint256Offset, - testUint256B, - ); - const newByteArrayBuffer = ethUtil.toBuffer(newByteArray); - const uint256FromOffsetBuffer = newByteArrayBuffer.slice(prefixByteArrayBuffer.byteLength); - const uint256FromOffset = new BigNumber( - ethUtil.addHexPrefix(ethUtil.bufferToHex(uint256FromOffsetBuffer)), - 16, - ); - return expect(uint256FromOffset).to.be.bignumber.equal(testUint256B); - }); - it('should fail if the byte array is too short to hold a uint256', async () => { - const offset = new BigNumber(0); - return expectContractCallFailedAsync( - libBytes.publicWriteUint256.callAsync(byteArrayShorterThan32Bytes, offset, testUint256), - RevertReason.LibBytesGreaterOrEqualTo32LengthRequired, - ); - }); - it('should fail if the length between the offset and end of the byte array is too short to hold a uint256', async () => { - const byteArray = byteArrayLongerThan32Bytes; - const badOffset = new BigNumber(ethUtil.toBuffer(byteArray).byteLength); - return expectContractCallFailedAsync( - libBytes.publicWriteUint256.callAsync(byteArray, badOffset, testUint256), - RevertReason.LibBytesGreaterOrEqualTo32LengthRequired, - ); - }); - }); - - describe('readBytes4', () => { - // AssertionError: expected promise to be rejected with an error including 'revert' but it was fulfilled with '0x08c379a0' - it('should revert if byte array has a length < 4', async () => { - const byteArrayLessThan4Bytes = '0x010101'; - const offset = new BigNumber(0); - return expectContractCallFailedAsync( - libBytes.publicReadBytes4.callAsync(byteArrayLessThan4Bytes, offset), - RevertReason.LibBytesGreaterOrEqualTo4LengthRequired, - ); - }); - it('should return the first 4 bytes of a byte array of arbitrary length', async () => { - const first4Bytes = await libBytes.publicReadBytes4.callAsync(byteArrayLongerThan32Bytes, new BigNumber(0)); - const expectedFirst4Bytes = byteArrayLongerThan32Bytes.slice(0, 10); - expect(first4Bytes).to.equal(expectedFirst4Bytes); - }); - it('should successfully read bytes4 when the bytes4 takes up the whole array', async () => { - const testBytes4Offset = new BigNumber(0); - const bytes4 = await libBytes.publicReadBytes4.callAsync(testBytes4, testBytes4Offset); - return expect(bytes4).to.be.equal(testBytes4); - }); - it('should successfully read bytes4 when it is offset in the array', async () => { - const bytes4ByteArrayBuffer = ethUtil.toBuffer(testBytes4); - const prefixByteArrayBuffer = ethUtil.toBuffer('0xabcdef'); - const combinedByteArrayBuffer = Buffer.concat([prefixByteArrayBuffer, bytes4ByteArrayBuffer]); - const combinedByteArray = ethUtil.bufferToHex(combinedByteArrayBuffer); - const testBytes4Offset = new BigNumber(prefixByteArrayBuffer.byteLength); - const bytes4 = await libBytes.publicReadBytes4.callAsync(combinedByteArray, testBytes4Offset); - return expect(bytes4).to.be.equal(testBytes4); - }); - it('should fail if the length between the offset and end of the byte array is too short to hold a bytes4', async () => { - const badOffset = new BigNumber(ethUtil.toBuffer(testBytes4).byteLength); - return expectContractCallFailedAsync( - libBytes.publicReadBytes4.callAsync(testBytes4, badOffset), - RevertReason.LibBytesGreaterOrEqualTo4LengthRequired, - ); - }); - }); - - describe('readBytesWithLength', () => { - it('should successfully read short, nested array of bytes when it takes up the whole array', async () => { - const testBytesOffset = new BigNumber(0); - const bytes = await libBytes.publicReadBytesWithLength.callAsync(shortTestBytes, testBytesOffset); - return expect(bytes).to.be.equal(shortData); - }); - it('should successfully read short, nested array of bytes when it is offset in the array', async () => { - const prefixByteArrayBuffer = ethUtil.toBuffer('0xabcdef'); - const combinedByteArrayBuffer = Buffer.concat([prefixByteArrayBuffer, shortTestBytesAsBuffer]); - const combinedByteArray = ethUtil.bufferToHex(combinedByteArrayBuffer); - const testUint256Offset = new BigNumber(prefixByteArrayBuffer.byteLength); - const bytes = await libBytes.publicReadBytesWithLength.callAsync(combinedByteArray, testUint256Offset); - return expect(bytes).to.be.equal(shortData); - }); - it('should successfully read a nested array of bytes - one word in length - when it takes up the whole array', async () => { - const testBytesOffset = new BigNumber(0); - const bytes = await libBytes.publicReadBytesWithLength.callAsync(wordOfTestBytes, testBytesOffset); - return expect(bytes).to.be.equal(wordOfData); - }); - it('should successfully read a nested array of bytes - one word in length - when it is offset in the array', async () => { - const prefixByteArrayBuffer = ethUtil.toBuffer('0xabcdef'); - const combinedByteArrayBuffer = Buffer.concat([prefixByteArrayBuffer, wordOfTestBytesAsBuffer]); - const combinedByteArray = ethUtil.bufferToHex(combinedByteArrayBuffer); - const testUint256Offset = new BigNumber(prefixByteArrayBuffer.byteLength); - const bytes = await libBytes.publicReadBytesWithLength.callAsync(combinedByteArray, testUint256Offset); - return expect(bytes).to.be.equal(wordOfData); - }); - it('should successfully read long, nested array of bytes when it takes up the whole array', async () => { - const testBytesOffset = new BigNumber(0); - const bytes = await libBytes.publicReadBytesWithLength.callAsync(longTestBytes, testBytesOffset); - return expect(bytes).to.be.equal(longData); - }); - it('should successfully read long, nested array of bytes when it is offset in the array', async () => { - const prefixByteArrayBuffer = ethUtil.toBuffer('0xabcdef'); - const combinedByteArrayBuffer = Buffer.concat([prefixByteArrayBuffer, longTestBytesAsBuffer]); - const combinedByteArray = ethUtil.bufferToHex(combinedByteArrayBuffer); - const testUint256Offset = new BigNumber(prefixByteArrayBuffer.byteLength); - const bytes = await libBytes.publicReadBytesWithLength.callAsync(combinedByteArray, testUint256Offset); - return expect(bytes).to.be.equal(longData); - }); - it('should fail if the byte array is too short to hold the length of a nested byte array', async () => { - // The length of the nested array is 32 bytes. By storing less than 32 bytes, a length cannot be read. - const offset = new BigNumber(0); - return expectContractCallFailedAsync( - libBytes.publicReadBytesWithLength.callAsync(byteArrayShorterThan32Bytes, offset), - RevertReason.LibBytesGreaterOrEqualTo32LengthRequired, - ); - }); - it('should fail if we store a nested byte array length, without a nested byte array', async () => { - const offset = new BigNumber(0); - return expectContractCallFailedAsync( - libBytes.publicReadBytesWithLength.callAsync(testBytes32, offset), - RevertReason.LibBytesGreaterOrEqualToNestedBytesLengthRequired, - ); - }); - it('should fail if the length between the offset and end of the byte array is too short to hold the length of a nested byte array', async () => { - const badOffset = new BigNumber(ethUtil.toBuffer(byteArrayShorterThan32Bytes).byteLength); - return expectContractCallFailedAsync( - libBytes.publicReadBytesWithLength.callAsync(byteArrayShorterThan32Bytes, badOffset), - RevertReason.LibBytesGreaterOrEqualTo32LengthRequired, - ); - }); - it('should fail if the length between the offset and end of the byte array is too short to hold the nested byte array', async () => { - const badOffset = new BigNumber(ethUtil.toBuffer(testBytes32).byteLength); - return expectContractCallFailedAsync( - libBytes.publicReadBytesWithLength.callAsync(testBytes32, badOffset), - RevertReason.LibBytesGreaterOrEqualTo32LengthRequired, - ); - }); - }); - - describe('writeBytesWithLength', () => { - it('should successfully write short, nested array of bytes when it takes up the whole array', async () => { - const testBytesOffset = new BigNumber(0); - const emptyByteArray = ethUtil.bufferToHex(new Buffer(shortTestBytesAsBuffer.byteLength)); - const bytesWritten = await libBytes.publicWriteBytesWithLength.callAsync( - emptyByteArray, - testBytesOffset, - shortData, - ); - const bytesRead = await libBytes.publicReadBytesWithLength.callAsync(bytesWritten, testBytesOffset); - return expect(bytesRead).to.be.equal(shortData); - }); - it('should successfully write short, nested array of bytes when it is offset in the array', async () => { - // Write a prefix to the array - const prefixData = '0xabcdef'; - const prefixDataAsBuffer = ethUtil.toBuffer(prefixData); - const prefixOffset = new BigNumber(0); - const emptyByteArray = ethUtil.bufferToHex( - new Buffer(prefixDataAsBuffer.byteLength + shortTestBytesAsBuffer.byteLength), - ); - let bytesWritten = await libBytes.publicWriteBytesWithLength.callAsync( - emptyByteArray, - prefixOffset, - prefixData, - ); - // Write data after prefix - const testBytesOffset = new BigNumber(prefixDataAsBuffer.byteLength); - bytesWritten = await libBytes.publicWriteBytesWithLength.callAsync( - bytesWritten, - testBytesOffset, - shortData, - ); - // Read data after prefix and validate - const bytes = await libBytes.publicReadBytesWithLength.callAsync(bytesWritten, testBytesOffset); - return expect(bytes).to.be.equal(shortData); - }); - it('should successfully write a nested array of bytes - one word in length - when it takes up the whole array', async () => { - const testBytesOffset = new BigNumber(0); - const emptyByteArray = ethUtil.bufferToHex(new Buffer(wordOfTestBytesAsBuffer.byteLength)); - const bytesWritten = await libBytes.publicWriteBytesWithLength.callAsync( - emptyByteArray, - testBytesOffset, - wordOfData, - ); - const bytesRead = await libBytes.publicReadBytesWithLength.callAsync(bytesWritten, testBytesOffset); - return expect(bytesRead).to.be.equal(wordOfData); - }); - it('should successfully write a nested array of bytes - one word in length - when it is offset in the array', async () => { - // Write a prefix to the array - const prefixData = '0xabcdef'; - const prefixDataAsBuffer = ethUtil.toBuffer(prefixData); - const prefixOffset = new BigNumber(0); - const emptyByteArray = ethUtil.bufferToHex( - new Buffer(prefixDataAsBuffer.byteLength + wordOfTestBytesAsBuffer.byteLength), - ); - let bytesWritten = await libBytes.publicWriteBytesWithLength.callAsync( - emptyByteArray, - prefixOffset, - prefixData, - ); - // Write data after prefix - const testBytesOffset = new BigNumber(prefixDataAsBuffer.byteLength); - bytesWritten = await libBytes.publicWriteBytesWithLength.callAsync( - bytesWritten, - testBytesOffset, - wordOfData, - ); - // Read data after prefix and validate - const bytes = await libBytes.publicReadBytesWithLength.callAsync(bytesWritten, testBytesOffset); - return expect(bytes).to.be.equal(wordOfData); - }); - it('should successfully write a long, nested bytes when it takes up the whole array', async () => { - const testBytesOffset = new BigNumber(0); - const emptyByteArray = ethUtil.bufferToHex(new Buffer(longTestBytesAsBuffer.byteLength)); - const bytesWritten = await libBytes.publicWriteBytesWithLength.callAsync( - emptyByteArray, - testBytesOffset, - longData, - ); - const bytesRead = await libBytes.publicReadBytesWithLength.callAsync(bytesWritten, testBytesOffset); - return expect(bytesRead).to.be.equal(longData); - }); - it('should successfully write long, nested array of bytes when it is offset in the array', async () => { - // Write a prefix to the array - const prefixData = '0xabcdef'; - const prefixDataAsBuffer = ethUtil.toBuffer(prefixData); - const prefixOffset = new BigNumber(0); - const emptyByteArray = ethUtil.bufferToHex( - new Buffer(prefixDataAsBuffer.byteLength + longTestBytesAsBuffer.byteLength), - ); - let bytesWritten = await libBytes.publicWriteBytesWithLength.callAsync( - emptyByteArray, - prefixOffset, - prefixData, - ); - // Write data after prefix - const testBytesOffset = new BigNumber(prefixDataAsBuffer.byteLength); - bytesWritten = await libBytes.publicWriteBytesWithLength.callAsync(bytesWritten, testBytesOffset, longData); - // Read data after prefix and validate - const bytes = await libBytes.publicReadBytesWithLength.callAsync(bytesWritten, testBytesOffset); - return expect(bytes).to.be.equal(longData); - }); - it('should fail if the byte array is too short to hold the length of a nested byte array', async () => { - const offset = new BigNumber(0); - const emptyByteArray = ethUtil.bufferToHex(new Buffer(1)); - return expectContractCallFailedAsync( - libBytes.publicWriteBytesWithLength.callAsync(emptyByteArray, offset, longData), - RevertReason.LibBytesGreaterOrEqualToNestedBytesLengthRequired, - ); - }); - it('should fail if the length between the offset and end of the byte array is too short to hold the length of a nested byte array', async () => { - const emptyByteArray = ethUtil.bufferToHex(new Buffer(shortTestBytesAsBuffer.byteLength)); - const badOffset = new BigNumber(ethUtil.toBuffer(shortTestBytesAsBuffer).byteLength); - return expectContractCallFailedAsync( - libBytes.publicWriteBytesWithLength.callAsync(emptyByteArray, badOffset, shortData), - RevertReason.LibBytesGreaterOrEqualToNestedBytesLengthRequired, - ); - }); - }); - - describe('memCopy', () => { - // Create memory 0x000102...FF - const memSize = 256; - // tslint:disable:no-shadowed-variable - const memory = new Uint8Array(memSize).map((_, i) => i); - const memHex = toHex(memory); - - // Reference implementation to test against - const refMemcpy = (mem: Uint8Array, dest: number, source: number, length: number): Uint8Array => - Uint8Array.from(mem).copyWithin(dest, source, source + length); - - // Test vectors: destination, source, length, job description - type Tests = Array<[number, number, number, string]>; - - const test = (tests: Tests) => - tests.forEach(([dest, source, length, job]) => - it(job, async () => { - const expected = refMemcpy(memory, dest, source, length); - const resultStr = await libBytes.testMemcpy.callAsync( - memHex, - new BigNumber(dest), - new BigNumber(source), - new BigNumber(length), - ); - const result = fromHex(resultStr); - expect(result).to.deep.equal(expected); - }), - ); - - test([[0, 0, 0, 'copies zero bytes with overlap']]); - - describe('copies forward', () => - test([ - [128, 0, 0, 'zero bytes'], - [128, 0, 1, 'one byte'], - [128, 0, 11, 'eleven bytes'], - [128, 0, 31, 'thirty-one bytes'], - [128, 0, 32, 'one word'], - [128, 0, 64, 'two words'], - [128, 0, 96, 'three words'], - [128, 0, 33, 'one word and one byte'], - [128, 0, 72, 'two words and eight bytes'], - [128, 0, 100, 'three words and four bytes'], - ])); - - describe('copies forward within one word', () => - test([ - [16, 0, 0, 'zero bytes'], - [16, 0, 1, 'one byte'], - [16, 0, 11, 'eleven bytes'], - [16, 0, 16, 'sixteen bytes'], - ])); - - describe('copies forward with one byte overlap', () => - test([ - [0, 0, 1, 'one byte'], - [10, 0, 11, 'eleven bytes'], - [30, 0, 31, 'thirty-one bytes'], - [31, 0, 32, 'one word'], - [32, 0, 33, 'one word and one byte'], - [71, 0, 72, 'two words and eight bytes'], - [99, 0, 100, 'three words and four bytes'], - ])); - - describe('copies forward with thirty-one bytes overlap', () => - test([ - [0, 0, 31, 'thirty-one bytes'], - [1, 0, 32, 'one word'], - [2, 0, 33, 'one word and one byte'], - [41, 0, 72, 'two words and eight bytes'], - [69, 0, 100, 'three words and four bytes'], - ])); - - describe('copies forward with one word overlap', () => - test([ - [0, 0, 32, 'one word'], - [1, 0, 33, 'one word and one byte'], - [41, 0, 72, 'two words and eight bytes'], - [69, 0, 100, 'three words and four bytes'], - ])); - - describe('copies forward with one word and one byte overlap', () => - test([ - [0, 0, 33, 'one word and one byte'], - [40, 0, 72, 'two words and eight bytes'], - [68, 0, 100, 'three words and four bytes'], - ])); - - describe('copies forward with two words overlap', () => - test([ - [0, 0, 64, 'two words'], - [8, 0, 72, 'two words and eight bytes'], - [36, 0, 100, 'three words and four bytes'], - ])); - - describe('copies forward within one word and one byte overlap', () => - test([[0, 0, 1, 'one byte'], [10, 0, 11, 'eleven bytes'], [15, 0, 16, 'sixteen bytes']])); - - describe('copies backward', () => - test([ - [0, 128, 0, 'zero bytes'], - [0, 128, 1, 'one byte'], - [0, 128, 11, 'eleven bytes'], - [0, 128, 31, 'thirty-one bytes'], - [0, 128, 32, 'one word'], - [0, 128, 64, 'two words'], - [0, 128, 96, 'three words'], - [0, 128, 33, 'one word and one byte'], - [0, 128, 72, 'two words and eight bytes'], - [0, 128, 100, 'three words and four bytes'], - ])); - - describe('copies backward within one word', () => - test([ - [0, 16, 0, 'zero bytes'], - [0, 16, 1, 'one byte'], - [0, 16, 11, 'eleven bytes'], - [0, 16, 16, 'sixteen bytes'], - ])); - - describe('copies backward with one byte overlap', () => - test([ - [0, 0, 1, 'one byte'], - [0, 10, 11, 'eleven bytes'], - [0, 30, 31, 'thirty-one bytes'], - [0, 31, 32, 'one word'], - [0, 32, 33, 'one word and one byte'], - [0, 71, 72, 'two words and eight bytes'], - [0, 99, 100, 'three words and four bytes'], - ])); - - describe('copies backward with thirty-one bytes overlap', () => - test([ - [0, 0, 31, 'thirty-one bytes'], - [0, 1, 32, 'one word'], - [0, 2, 33, 'one word and one byte'], - [0, 41, 72, 'two words and eight bytes'], - [0, 69, 100, 'three words and four bytes'], - ])); - - describe('copies backward with one word overlap', () => - test([ - [0, 0, 32, 'one word'], - [0, 1, 33, 'one word and one byte'], - [0, 41, 72, 'two words and eight bytes'], - [0, 69, 100, 'three words and four bytes'], - ])); - - describe('copies backward with one word and one byte overlap', () => - test([ - [0, 0, 33, 'one word and one byte'], - [0, 40, 72, 'two words and eight bytes'], - [0, 68, 100, 'three words and four bytes'], - ])); - - describe('copies backward with two words overlap', () => - test([ - [0, 0, 64, 'two words'], - [0, 8, 72, 'two words and eight bytes'], - [0, 36, 100, 'three words and four bytes'], - ])); - - describe('copies forward within one word and one byte overlap', () => - test([[0, 0, 1, 'one byte'], [0, 10, 11, 'eleven bytes'], [0, 15, 16, 'sixteen bytes']])); - }); -}); -// tslint:disable:max-file-line-count diff --git a/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/multisig/multi_sig_with_time_lock.ts b/contracts/core/test/multisig/multi_sig_with_time_lock.ts deleted file mode 100644 index 1c0cb0515..000000000 --- a/contracts/core/test/multisig/multi_sig_with_time_lock.ts +++ /dev/null @@ -1,347 +0,0 @@ -import { BlockchainLifecycle } from '@0x/dev-utils'; -import { RevertReason } from '@0x/types'; -import { BigNumber } from '@0x/utils'; -import * as chai from 'chai'; -import { LogWithDecodedArgs } from 'ethereum-types'; -import * as _ from 'lodash'; - -import { DummyERC20TokenContract } from '../../generated-wrappers/dummy_erc20_token'; -import { - MultiSigWalletWithTimeLockConfirmationEventArgs, - MultiSigWalletWithTimeLockConfirmationTimeSetEventArgs, - MultiSigWalletWithTimeLockContract, - MultiSigWalletWithTimeLockExecutionEventArgs, - MultiSigWalletWithTimeLockExecutionFailureEventArgs, - MultiSigWalletWithTimeLockSubmissionEventArgs, -} from '../../generated-wrappers/multi_sig_wallet_with_time_lock'; -import { artifacts } from '../../src/artifacts'; -import { expectTransactionFailedAsync, expectTransactionFailedWithoutReasonAsync } from '../utils/assertions'; -import { increaseTimeAndMineBlockAsync } from '../utils/block_timestamp'; -import { chaiSetup } from '../utils/chai_setup'; -import { constants } from '../utils/constants'; -import { MultiSigWrapper } from '../utils/multi_sig_wrapper'; -import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper'; - -chaiSetup.configure(); -const expect = chai.expect; -const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); -// tslint:disable:no-unnecessary-type-assertion -describe('MultiSigWalletWithTimeLock', () => { - let owners: string[]; - let notOwner: string; - const REQUIRED_APPROVALS = new BigNumber(2); - const SECONDS_TIME_LOCKED = new BigNumber(1000000); - - before(async () => { - await blockchainLifecycle.startAsync(); - }); - after(async () => { - await blockchainLifecycle.revertAsync(); - }); - before(async () => { - const accounts = await web3Wrapper.getAvailableAddressesAsync(); - owners = [accounts[0], accounts[1], accounts[2]]; - notOwner = accounts[3]; - }); - - let multiSig: MultiSigWalletWithTimeLockContract; - let multiSigWrapper: MultiSigWrapper; - - beforeEach(async () => { - await blockchainLifecycle.startAsync(); - }); - afterEach(async () => { - await blockchainLifecycle.revertAsync(); - }); - - describe('external_call', () => { - it('should be internal', async () => { - const secondsTimeLocked = new BigNumber(0); - multiSig = await MultiSigWalletWithTimeLockContract.deployFrom0xArtifactAsync( - artifacts.MultiSigWalletWithTimeLock, - provider, - txDefaults, - owners, - REQUIRED_APPROVALS, - secondsTimeLocked, - ); - expect(_.isUndefined((multiSig as any).external_call)).to.be.equal(true); - }); - }); - describe('confirmTransaction', () => { - let txId: BigNumber; - beforeEach(async () => { - const secondsTimeLocked = new BigNumber(0); - multiSig = await MultiSigWalletWithTimeLockContract.deployFrom0xArtifactAsync( - artifacts.MultiSigWalletWithTimeLock, - provider, - txDefaults, - owners, - REQUIRED_APPROVALS, - secondsTimeLocked, - ); - multiSigWrapper = new MultiSigWrapper(multiSig, provider); - const destination = notOwner; - const data = constants.NULL_BYTES; - const txReceipt = await multiSigWrapper.submitTransactionAsync(destination, data, owners[0]); - txId = (txReceipt.logs[0] as LogWithDecodedArgs<MultiSigWalletWithTimeLockSubmissionEventArgs>).args - .transactionId; - }); - it('should revert if called by a non-owner', async () => { - await expectTransactionFailedWithoutReasonAsync(multiSigWrapper.confirmTransactionAsync(txId, notOwner)); - }); - it('should revert if transaction does not exist', async () => { - const nonexistentTxId = new BigNumber(123456789); - await expectTransactionFailedWithoutReasonAsync( - multiSigWrapper.confirmTransactionAsync(nonexistentTxId, owners[1]), - ); - }); - it('should revert if transaction is already confirmed by caller', async () => { - await expectTransactionFailedWithoutReasonAsync(multiSigWrapper.confirmTransactionAsync(txId, owners[0])); - }); - it('should confirm transaction for caller and log a Confirmation event', async () => { - const txReceipt = await multiSigWrapper.confirmTransactionAsync(txId, owners[1]); - const log = txReceipt.logs[0] as LogWithDecodedArgs<MultiSigWalletWithTimeLockConfirmationEventArgs>; - expect(log.event).to.be.equal('Confirmation'); - expect(log.args.sender).to.be.equal(owners[1]); - expect(log.args.transactionId).to.be.bignumber.equal(txId); - }); - it('should revert if fully confirmed', async () => { - await multiSigWrapper.confirmTransactionAsync(txId, owners[1]); - await expectTransactionFailedAsync( - multiSigWrapper.confirmTransactionAsync(txId, owners[2]), - RevertReason.TxFullyConfirmed, - ); - }); - it('should set the confirmation time of the transaction if it becomes fully confirmed', async () => { - const txReceipt = await multiSigWrapper.confirmTransactionAsync(txId, owners[1]); - const blockNum = await web3Wrapper.getBlockNumberAsync(); - const timestamp = new BigNumber(await web3Wrapper.getBlockTimestampAsync(blockNum)); - const log = txReceipt.logs[1] as LogWithDecodedArgs<MultiSigWalletWithTimeLockConfirmationTimeSetEventArgs>; - expect(log.args.confirmationTime).to.be.bignumber.equal(timestamp); - expect(log.args.transactionId).to.be.bignumber.equal(txId); - }); - }); - describe('executeTransaction', () => { - let txId: BigNumber; - const secondsTimeLocked = new BigNumber(1000000); - beforeEach(async () => { - multiSig = await MultiSigWalletWithTimeLockContract.deployFrom0xArtifactAsync( - artifacts.MultiSigWalletWithTimeLock, - provider, - txDefaults, - owners, - REQUIRED_APPROVALS, - secondsTimeLocked, - ); - multiSigWrapper = new MultiSigWrapper(multiSig, provider); - const destination = notOwner; - const data = constants.NULL_BYTES; - const txReceipt = await multiSigWrapper.submitTransactionAsync(destination, data, owners[0]); - txId = (txReceipt.logs[0] as LogWithDecodedArgs<MultiSigWalletWithTimeLockSubmissionEventArgs>).args - .transactionId; - }); - it('should revert if transaction has not been fully confirmed', async () => { - await increaseTimeAndMineBlockAsync(secondsTimeLocked.toNumber()); - await expectTransactionFailedAsync( - multiSigWrapper.executeTransactionAsync(txId, owners[1]), - RevertReason.TxNotFullyConfirmed, - ); - }); - it('should revert if time lock has not passed', async () => { - await multiSigWrapper.confirmTransactionAsync(txId, owners[1]); - await expectTransactionFailedAsync( - multiSigWrapper.executeTransactionAsync(txId, owners[1]), - RevertReason.TimeLockIncomplete, - ); - }); - it('should execute a transaction and log an Execution event if successful and called by owner', async () => { - await multiSigWrapper.confirmTransactionAsync(txId, owners[1]); - await increaseTimeAndMineBlockAsync(secondsTimeLocked.toNumber()); - const txReceipt = await multiSigWrapper.executeTransactionAsync(txId, owners[1]); - const log = txReceipt.logs[0] as LogWithDecodedArgs<MultiSigWalletWithTimeLockExecutionEventArgs>; - expect(log.event).to.be.equal('Execution'); - expect(log.args.transactionId).to.be.bignumber.equal(txId); - }); - it('should execute a transaction and log an Execution event if successful and called by non-owner', async () => { - await multiSigWrapper.confirmTransactionAsync(txId, owners[1]); - await increaseTimeAndMineBlockAsync(secondsTimeLocked.toNumber()); - const txReceipt = await multiSigWrapper.executeTransactionAsync(txId, notOwner); - const log = txReceipt.logs[0] as LogWithDecodedArgs<MultiSigWalletWithTimeLockExecutionEventArgs>; - expect(log.event).to.be.equal('Execution'); - expect(log.args.transactionId).to.be.bignumber.equal(txId); - }); - it('should revert if a required confirmation is revoked before executeTransaction is called', async () => { - await multiSigWrapper.confirmTransactionAsync(txId, owners[1]); - await increaseTimeAndMineBlockAsync(secondsTimeLocked.toNumber()); - await multiSigWrapper.revokeConfirmationAsync(txId, owners[0]); - await expectTransactionFailedAsync( - multiSigWrapper.executeTransactionAsync(txId, owners[1]), - RevertReason.TxNotFullyConfirmed, - ); - }); - it('should revert if transaction has been executed', async () => { - await multiSigWrapper.confirmTransactionAsync(txId, owners[1]); - await increaseTimeAndMineBlockAsync(secondsTimeLocked.toNumber()); - const txReceipt = await multiSigWrapper.executeTransactionAsync(txId, owners[1]); - const log = txReceipt.logs[0] as LogWithDecodedArgs<MultiSigWalletWithTimeLockExecutionEventArgs>; - expect(log.args.transactionId).to.be.bignumber.equal(txId); - await expectTransactionFailedWithoutReasonAsync(multiSigWrapper.executeTransactionAsync(txId, owners[1])); - }); - it("should log an ExecutionFailure event and not update the transaction's execution state if unsuccessful", async () => { - const contractWithoutFallback = await DummyERC20TokenContract.deployFrom0xArtifactAsync( - artifacts.DummyERC20Token, - provider, - txDefaults, - constants.DUMMY_TOKEN_NAME, - constants.DUMMY_TOKEN_SYMBOL, - constants.DUMMY_TOKEN_DECIMALS, - constants.DUMMY_TOKEN_TOTAL_SUPPLY, - ); - const data = constants.NULL_BYTES; - const value = new BigNumber(10); - const submissionTxReceipt = await multiSigWrapper.submitTransactionAsync( - contractWithoutFallback.address, - data, - owners[0], - { value }, - ); - const newTxId = (submissionTxReceipt.logs[0] as LogWithDecodedArgs< - MultiSigWalletWithTimeLockSubmissionEventArgs - >).args.transactionId; - await multiSigWrapper.confirmTransactionAsync(newTxId, owners[1]); - await increaseTimeAndMineBlockAsync(secondsTimeLocked.toNumber()); - const txReceipt = await multiSigWrapper.executeTransactionAsync(newTxId, owners[1]); - const executionFailureLog = txReceipt.logs[0] as LogWithDecodedArgs< - MultiSigWalletWithTimeLockExecutionFailureEventArgs - >; - expect(executionFailureLog.event).to.be.equal('ExecutionFailure'); - expect(executionFailureLog.args.transactionId).to.be.bignumber.equal(newTxId); - }); - }); - describe('changeTimeLock', () => { - describe('initially non-time-locked', async () => { - before(async () => { - await blockchainLifecycle.startAsync(); - }); - after(async () => { - await blockchainLifecycle.revertAsync(); - }); - before('deploy a wallet', async () => { - const secondsTimeLocked = new BigNumber(0); - multiSig = await MultiSigWalletWithTimeLockContract.deployFrom0xArtifactAsync( - artifacts.MultiSigWalletWithTimeLock, - provider, - txDefaults, - owners, - REQUIRED_APPROVALS, - secondsTimeLocked, - ); - multiSigWrapper = new MultiSigWrapper(multiSig, provider); - }); - - it('should throw when not called by wallet', async () => { - return expectTransactionFailedWithoutReasonAsync( - multiSig.changeTimeLock.sendTransactionAsync(SECONDS_TIME_LOCKED, { from: owners[0] }), - ); - }); - - it('should throw without enough confirmations', async () => { - const destination = multiSig.address; - const changeTimeLockData = multiSig.changeTimeLock.getABIEncodedTransactionData(SECONDS_TIME_LOCKED); - const res = await multiSigWrapper.submitTransactionAsync(destination, changeTimeLockData, owners[0]); - const log = res.logs[0] as LogWithDecodedArgs<MultiSigWalletWithTimeLockSubmissionEventArgs>; - const txId = log.args.transactionId; - return expectTransactionFailedAsync( - multiSig.executeTransaction.sendTransactionAsync(txId, { from: owners[0] }), - RevertReason.TxNotFullyConfirmed, - ); - }); - - it('should set confirmation time with enough confirmations', async () => { - const destination = multiSig.address; - const changeTimeLockData = multiSig.changeTimeLock.getABIEncodedTransactionData(SECONDS_TIME_LOCKED); - const subRes = await multiSigWrapper.submitTransactionAsync(destination, changeTimeLockData, owners[0]); - const subLog = subRes.logs[0] as LogWithDecodedArgs<MultiSigWalletWithTimeLockSubmissionEventArgs>; - const txId = subLog.args.transactionId; - - const confirmRes = await multiSigWrapper.confirmTransactionAsync(txId, owners[1]); - expect(confirmRes.logs).to.have.length(2); - - const blockNum = await web3Wrapper.getBlockNumberAsync(); - const blockInfo = await web3Wrapper.getBlockIfExistsAsync(blockNum); - if (_.isUndefined(blockInfo)) { - throw new Error(`Unexpectedly failed to fetch block at #${blockNum}`); - } - const timestamp = new BigNumber(blockInfo.timestamp); - const confirmationTimeBigNum = new BigNumber(await multiSig.confirmationTimes.callAsync(txId)); - - expect(timestamp).to.be.bignumber.equal(confirmationTimeBigNum); - }); - - it('should be executable with enough confirmations and secondsTimeLocked of 0', async () => { - const destination = multiSig.address; - const changeTimeLockData = multiSig.changeTimeLock.getABIEncodedTransactionData(SECONDS_TIME_LOCKED); - const subRes = await multiSigWrapper.submitTransactionAsync(destination, changeTimeLockData, owners[0]); - const subLog = subRes.logs[0] as LogWithDecodedArgs<MultiSigWalletWithTimeLockSubmissionEventArgs>; - const txId = subLog.args.transactionId; - - await multiSigWrapper.confirmTransactionAsync(txId, owners[1]); - await multiSigWrapper.executeTransactionAsync(txId, owners[1]); - - const secondsTimeLocked = new BigNumber(await multiSig.secondsTimeLocked.callAsync()); - expect(secondsTimeLocked).to.be.bignumber.equal(SECONDS_TIME_LOCKED); - }); - }); - describe('initially time-locked', async () => { - before(async () => { - await blockchainLifecycle.startAsync(); - }); - after(async () => { - await blockchainLifecycle.revertAsync(); - }); - let txId: BigNumber; - const newSecondsTimeLocked = new BigNumber(0); - before('deploy a wallet, submit transaction to change timelock, and confirm the transaction', async () => { - multiSig = await MultiSigWalletWithTimeLockContract.deployFrom0xArtifactAsync( - artifacts.MultiSigWalletWithTimeLock, - provider, - txDefaults, - owners, - REQUIRED_APPROVALS, - SECONDS_TIME_LOCKED, - ); - multiSigWrapper = new MultiSigWrapper(multiSig, provider); - - const changeTimeLockData = multiSig.changeTimeLock.getABIEncodedTransactionData(newSecondsTimeLocked); - const res = await multiSigWrapper.submitTransactionAsync( - multiSig.address, - changeTimeLockData, - owners[0], - ); - const log = res.logs[0] as LogWithDecodedArgs<MultiSigWalletWithTimeLockSubmissionEventArgs>; - txId = log.args.transactionId; - await multiSigWrapper.confirmTransactionAsync(txId, owners[1]); - }); - - it('should throw if it has enough confirmations but is not past the time lock', async () => { - return expectTransactionFailedAsync( - multiSig.executeTransaction.sendTransactionAsync(txId, { from: owners[0] }), - RevertReason.TimeLockIncomplete, - ); - }); - - it('should execute if it has enough confirmations and is past the time lock', async () => { - await increaseTimeAndMineBlockAsync(SECONDS_TIME_LOCKED.toNumber()); - await web3Wrapper.awaitTransactionSuccessAsync( - await multiSig.executeTransaction.sendTransactionAsync(txId, { from: owners[0] }), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - - const secondsTimeLocked = new BigNumber(await multiSig.secondsTimeLocked.callAsync()); - expect(secondsTimeLocked).to.be.bignumber.equal(newSecondsTimeLocked); - }); - }); - }); -}); -// tslint:enable:no-unnecessary-type-assertion diff --git a/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/abstract_asset_wrapper.ts b/contracts/core/test/utils/abstract_asset_wrapper.ts deleted file mode 100644 index 4b56a8502..000000000 --- a/contracts/core/test/utils/abstract_asset_wrapper.ts +++ /dev/null @@ -1,3 +0,0 @@ -export abstract class AbstractAssetWrapper { - public abstract getProxyId(): string; -} diff --git a/contracts/core/test/utils/address_utils.ts b/contracts/core/test/utils/address_utils.ts deleted file mode 100644 index 634da0c16..000000000 --- a/contracts/core/test/utils/address_utils.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { generatePseudoRandomSalt } from '@0x/order-utils'; -import { crypto } from '@0x/order-utils/lib/src/crypto'; - -export const addressUtils = { - generatePseudoRandomAddress(): string { - const randomBigNum = generatePseudoRandomSalt(); - const randomBuff = crypto.solSHA3([randomBigNum]); - const randomAddress = `0x${randomBuff.slice(0, 20).toString('hex')}`; - return randomAddress; - }, -}; diff --git a/contracts/core/test/utils/assertions.ts b/contracts/core/test/utils/assertions.ts deleted file mode 100644 index 5b1cedfcc..000000000 --- a/contracts/core/test/utils/assertions.ts +++ /dev/null @@ -1,199 +0,0 @@ -import { RevertReason } from '@0x/types'; -import { logUtils } from '@0x/utils'; -import { NodeType } from '@0x/web3-wrapper'; -import * as chai from 'chai'; -import { TransactionReceipt, TransactionReceiptStatus, TransactionReceiptWithDecodedLogs } from 'ethereum-types'; -import * as _ from 'lodash'; - -import { web3Wrapper } from './web3_wrapper'; - -const expect = chai.expect; - -let nodeType: NodeType | undefined; - -// Represents the return value of a `sendTransaction` call. The Promise should -// resolve with either a transaction receipt or a transaction hash. -export type sendTransactionResult = Promise<TransactionReceipt | TransactionReceiptWithDecodedLogs | string>; - -/** - * Returns ganacheError if the backing Ethereum node is Ganache and gethError - * if it is Geth. - * @param ganacheError the error to be returned if the backing node is Ganache. - * @param gethError the error to be returned if the backing node is Geth. - * @returns either the given ganacheError or gethError depending on the backing - * node. - */ -async function _getGanacheOrGethError(ganacheError: string, gethError: string): Promise<string> { - if (_.isUndefined(nodeType)) { - nodeType = await web3Wrapper.getNodeTypeAsync(); - } - switch (nodeType) { - case NodeType.Ganache: - return ganacheError; - case NodeType.Geth: - return gethError; - default: - throw new Error(`Unknown node type: ${nodeType}`); - } -} - -async function _getInsufficientFundsErrorMessageAsync(): Promise<string> { - return _getGanacheOrGethError("sender doesn't have enough funds", 'insufficient funds'); -} - -async function _getTransactionFailedErrorMessageAsync(): Promise<string> { - return _getGanacheOrGethError('revert', 'always failing transaction'); -} - -async function _getContractCallFailedErrorMessageAsync(): Promise<string> { - return _getGanacheOrGethError('revert', 'Contract call failed'); -} - -/** - * Returns the expected error message for an 'invalid opcode' resulting from a - * contract call. The exact error message depends on the backing Ethereum node. - */ -export async function getInvalidOpcodeErrorMessageForCallAsync(): Promise<string> { - return _getGanacheOrGethError('invalid opcode', 'Contract call failed'); -} - -/** - * Returns the expected error message for the given revert reason resulting from - * a sendTransaction call. The exact error message depends on the backing - * Ethereum node and whether it supports revert reasons. - * @param reason a specific revert reason. - * @returns the expected error message. - */ -export async function getRevertReasonOrErrorMessageForSendTransactionAsync(reason: RevertReason): Promise<string> { - return _getGanacheOrGethError(reason, 'always failing transaction'); -} - -/** - * Rejects if the given Promise does not reject with an error indicating - * insufficient funds. - * @param p a promise resulting from a contract call or sendTransaction call. - * @returns a new Promise which will reject if the conditions are not met and - * otherwise resolve with no value. - */ -export async function expectInsufficientFundsAsync<T>(p: Promise<T>): Promise<void> { - const errMessage = await _getInsufficientFundsErrorMessageAsync(); - return expect(p).to.be.rejectedWith(errMessage); -} - -/** - * Resolves if the the sendTransaction call fails with the given revert reason. - * However, since Geth does not support revert reasons for sendTransaction, this - * falls back to expectTransactionFailedWithoutReasonAsync if the backing - * Ethereum node is Geth. - * @param p a Promise resulting from a sendTransaction call - * @param reason a specific revert reason - * @returns a new Promise which will reject if the conditions are not met and - * otherwise resolve with no value. - */ -export async function expectTransactionFailedAsync(p: sendTransactionResult, reason: RevertReason): Promise<void> { - // HACK(albrow): This dummy `catch` should not be necessary, but if you - // remove it, there is an uncaught exception and the Node process will - // forcibly exit. It's possible this is a false positive in - // make-promises-safe. - p.catch(e => { - _.noop(e); - }); - - if (_.isUndefined(nodeType)) { - nodeType = await web3Wrapper.getNodeTypeAsync(); - } - switch (nodeType) { - case NodeType.Ganache: - return expect(p).to.be.rejectedWith(reason); - case NodeType.Geth: - logUtils.warn( - 'WARNING: Geth does not support revert reasons for sendTransaction. This test will pass if the transaction fails for any reason.', - ); - return expectTransactionFailedWithoutReasonAsync(p); - default: - throw new Error(`Unknown node type: ${nodeType}`); - } -} - -/** - * Resolves if the transaction fails without a revert reason, or if the - * corresponding transactionReceipt has a status of 0 or '0', indicating - * failure. - * @param p a Promise resulting from a sendTransaction call - * @returns a new Promise which will reject if the conditions are not met and - * otherwise resolve with no value. - */ -export async function expectTransactionFailedWithoutReasonAsync(p: sendTransactionResult): Promise<void> { - return p - .then(async result => { - let txReceiptStatus: TransactionReceiptStatus; - if (_.isString(result)) { - // Result is a txHash. We need to make a web3 call to get the - // receipt, then get the status from the receipt. - const txReceipt = await web3Wrapper.awaitTransactionMinedAsync(result); - txReceiptStatus = txReceipt.status; - } else if ('status' in result) { - // Result is a transaction receipt, so we can get the status - // directly. - txReceiptStatus = result.status; - } else { - throw new Error('Unexpected result type: ' + typeof result); - } - expect(_.toString(txReceiptStatus)).to.equal( - '0', - 'Expected transaction to fail but receipt had a non-zero status, indicating success', - ); - }) - .catch(async err => { - // If the promise rejects, we expect a specific error message, - // depending on the backing Ethereum node type. - const errMessage = await _getTransactionFailedErrorMessageAsync(); - expect(err.message).to.include(errMessage); - }); -} - -/** - * Resolves if the the contract call fails with the given revert reason. - * @param p a Promise resulting from a contract call - * @param reason a specific revert reason - * @returns a new Promise which will reject if the conditions are not met and - * otherwise resolve with no value. - */ -export async function expectContractCallFailedAsync<T>(p: Promise<T>, reason: RevertReason): Promise<void> { - return expect(p).to.be.rejectedWith(reason); -} - -/** - * Resolves if the contract call fails without a revert reason. - * @param p a Promise resulting from a contract call - * @returns a new Promise which will reject if the conditions are not met and - * otherwise resolve with no value. - */ -export async function expectContractCallFailedWithoutReasonAsync<T>(p: Promise<T>): Promise<void> { - const errMessage = await _getContractCallFailedErrorMessageAsync(); - return expect(p).to.be.rejectedWith(errMessage); -} - -/** - * Resolves if the contract creation/deployment fails without a revert reason. - * @param p a Promise resulting from a contract creation/deployment - * @returns a new Promise which will reject if the conditions are not met and - * otherwise resolve with no value. - */ -export async function expectContractCreationFailedAsync<T>( - p: sendTransactionResult, - reason: RevertReason, -): Promise<void> { - return expectTransactionFailedAsync(p, reason); -} - -/** - * Resolves if the contract creation/deployment fails without a revert reason. - * @param p a Promise resulting from a contract creation/deployment - * @returns a new Promise which will reject if the conditions are not met and - * otherwise resolve with no value. - */ -export async function expectContractCreationFailedWithoutReasonAsync<T>(p: Promise<T>): Promise<void> { - const errMessage = await _getTransactionFailedErrorMessageAsync(); - return expect(p).to.be.rejectedWith(errMessage); -} diff --git a/contracts/core/test/utils/multi_sig_wrapper.ts b/contracts/core/test/utils/asset_proxy_owner_wrapper.ts index 74fd3b4d6..d5aaaf519 100644 --- a/contracts/core/test/utils/multi_sig_wrapper.ts +++ b/contracts/core/test/utils/asset_proxy_owner_wrapper.ts @@ -1,21 +1,20 @@ +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 { artifacts } from '../../src/artifacts'; -import { LogDecoder } from './log_decoder'; - -export class MultiSigWrapper { - private readonly _multiSig: MultiSigWalletContract; +export class AssetProxyOwnerWrapper { + private readonly _assetProxyOwner: AssetProxyOwnerContract; private readonly _web3Wrapper: Web3Wrapper; private readonly _logDecoder: LogDecoder; - constructor(multiSigContract: MultiSigWalletContract, provider: Provider) { - this._multiSig = multiSigContract; + constructor(assetproxyOwnerContract: AssetProxyOwnerContract, provider: Provider) { + this._assetProxyOwner = assetproxyOwnerContract; this._web3Wrapper = new Web3Wrapper(provider); - this._logDecoder = new LogDecoder(this._web3Wrapper); + this._logDecoder = new LogDecoder(this._web3Wrapper, artifacts); } public async submitTransactionAsync( destination: string, @@ -24,19 +23,19 @@ export class MultiSigWrapper { opts: { value?: BigNumber } = {}, ): Promise<TransactionReceiptWithDecodedLogs> { const value = _.isUndefined(opts.value) ? new BigNumber(0) : opts.value; - const txHash = await this._multiSig.submitTransaction.sendTransactionAsync(destination, value, data, { + 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._multiSig.confirmTransaction.sendTransactionAsync(txId, { from }); + 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._multiSig.revokeConfirmation.sendTransactionAsync(txId, { from }); + const txHash = await this._assetProxyOwner.revokeConfirmation.sendTransactionAsync(txId, { from }); const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash); return tx; } @@ -45,7 +44,7 @@ export class MultiSigWrapper { from: string, opts: { gas?: number } = {}, ): Promise<TransactionReceiptWithDecodedLogs> { - const txHash = await this._multiSig.executeTransaction.sendTransactionAsync(txId, { + const txHash = await this._assetProxyOwner.executeTransaction.sendTransactionAsync(txId, { from, gas: opts.gas, }); @@ -58,9 +57,12 @@ export class MultiSigWrapper { ): Promise<TransactionReceiptWithDecodedLogs> { // tslint:disable-next-line:no-unnecessary-type-assertion const txHash = await (this - ._multiSig as AssetProxyOwnerContract).executeRemoveAuthorizedAddressAtIndex.sendTransactionAsync(txId, { - from, - }); + ._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/block_timestamp.ts b/contracts/core/test/utils/block_timestamp.ts deleted file mode 100644 index 66c13eed1..000000000 --- a/contracts/core/test/utils/block_timestamp.ts +++ /dev/null @@ -1,43 +0,0 @@ -import * as _ from 'lodash'; - -import { constants } from './constants'; -import { web3Wrapper } from './web3_wrapper'; - -let firstAccount: string | undefined; - -/** - * Increases time by the given number of seconds and then mines a block so that - * the current block timestamp has the offset applied. - * @param seconds the number of seconds by which to incrase the time offset. - * @returns a new Promise which will resolve with the new total time offset or - * reject if the time could not be increased. - */ -export async function increaseTimeAndMineBlockAsync(seconds: number): Promise<number> { - if (_.isUndefined(firstAccount)) { - const accounts = await web3Wrapper.getAvailableAddressesAsync(); - firstAccount = accounts[0]; - } - - const offset = await web3Wrapper.increaseTimeAsync(seconds); - // Note: we need to send a transaction after increasing time so - // that a block is actually mined. The contract looks at the - // last mined block for the timestamp. - await web3Wrapper.awaitTransactionSuccessAsync( - await web3Wrapper.sendTransactionAsync({ from: firstAccount, to: firstAccount, value: 0 }), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - - return offset; -} - -/** - * Returns the timestamp of the latest block in seconds since the Unix epoch. - * @returns a new Promise which will resolve with the timestamp in seconds. - */ -export async function getLatestBlockTimestampAsync(): Promise<number> { - const currentBlockIfExists = await web3Wrapper.getBlockIfExistsAsync('latest'); - if (_.isUndefined(currentBlockIfExists)) { - throw new Error(`Unable to fetch latest block.`); - } - return currentBlockIfExists.timestamp; -} diff --git a/contracts/core/test/utils/chai_setup.ts b/contracts/core/test/utils/chai_setup.ts deleted file mode 100644 index 1a8733093..000000000 --- a/contracts/core/test/utils/chai_setup.ts +++ /dev/null @@ -1,13 +0,0 @@ -import * as chai from 'chai'; -import chaiAsPromised = require('chai-as-promised'); -import ChaiBigNumber = require('chai-bignumber'); -import * as dirtyChai from 'dirty-chai'; - -export const chaiSetup = { - configure(): void { - chai.config.includeStack = true; - chai.use(ChaiBigNumber()); - chai.use(dirtyChai); - chai.use(chaiAsPromised); - }, -}; diff --git a/contracts/core/test/utils/combinatorial_utils.ts b/contracts/core/test/utils/combinatorial_utils.ts deleted file mode 100644 index bb1b55b4d..000000000 --- a/contracts/core/test/utils/combinatorial_utils.ts +++ /dev/null @@ -1,113 +0,0 @@ -import { BigNumber } from '@0x/utils'; -import * as combinatorics from 'js-combinatorics'; - -import { testWithReferenceFuncAsync } from './test_with_reference'; - -// A set of values corresponding to the uint256 type in Solidity. This set -// contains some notable edge cases, including some values which will overflow -// the uint256 type when used in different mathematical operations. -export const uint256Values = [ - new BigNumber(0), - new BigNumber(1), - new BigNumber(2), - // Non-trivial big number. - new BigNumber(2).pow(64), - // Max that does not overflow when squared. - new BigNumber(2).pow(128).minus(1), - // Min that does overflow when squared. - new BigNumber(2).pow(128), - // Max that does not overflow when doubled. - new BigNumber(2).pow(255).minus(1), - // Min that does overflow when doubled. - new BigNumber(2).pow(255), - // Max that does not overflow. - new BigNumber(2).pow(256).minus(1), -]; - -// A set of values corresponding to the bytes32 type in Solidity. -export const bytes32Values = [ - // Min - '0x0000000000000000000000000000000000000000000000000000000000000000', - '0x0000000000000000000000000000000000000000000000000000000000000001', - '0x0000000000000000000000000000000000000000000000000000000000000002', - // Non-trivial big number. - '0x000000000000f000000000000000000000000000000000000000000000000000', - // Max - '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff', -]; - -export async function testCombinatoriallyWithReferenceFuncAsync<P0, P1, R>( - name: string, - referenceFunc: (p0: P0, p1: P1) => Promise<R>, - testFunc: (p0: P0, p1: P1) => Promise<R>, - allValues: [P0[], P1[]], -): Promise<void>; -export async function testCombinatoriallyWithReferenceFuncAsync<P0, P1, P2, R>( - name: string, - referenceFunc: (p0: P0, p1: P1, p2: P2) => Promise<R>, - testFunc: (p0: P0, p1: P1, p2: P2) => Promise<R>, - allValues: [P0[], P1[], P2[]], -): Promise<void>; -export async function testCombinatoriallyWithReferenceFuncAsync<P0, P1, P2, P3, R>( - name: string, - referenceFunc: (p0: P0, p1: P1, p2: P2, p3: P3) => Promise<R>, - testFunc: (p0: P0, p1: P1, p2: P2, p3: P3) => Promise<R>, - allValues: [P0[], P1[], P2[], P3[]], -): Promise<void>; -export async function testCombinatoriallyWithReferenceFuncAsync<P0, P1, P2, P3, P4, R>( - name: string, - referenceFunc: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4) => Promise<R>, - testFunc: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4) => Promise<R>, - allValues: [P0[], P1[], P2[], P3[], P4[]], -): Promise<void>; - -/** - * Uses combinatorics to test the behavior of a test function by comparing it to - * the expected behavior (defined by a reference function) for a large number of - * possible input values. - * - * First generates test cases by taking the cartesian product of the given - * values. Each test case is a set of N values corresponding to the N arguments - * for the test func and the reference func. For each test case, first the - * reference function will be called to obtain an "expected result", or if the - * reference function throws/rejects, an "expected error". Next, the test - * function will be called to obtain an "actual result", or if the test function - * throws/rejects, an "actual error". Each test case passes if at least one of - * the following conditions is met: - * - * 1) Neither the reference function or the test function throw and the - * "expected result" equals the "actual result". - * - * 2) Both the reference function and the test function throw and the "actual - * error" message *contains* the "expected error" message. - * - * The first test case which does not meet one of these conditions will cause - * the entire test to fail and this function will throw/reject. - * - * @param referenceFuncAsync a reference function implemented in pure - * JavaScript/TypeScript which accepts N arguments and returns the "expected - * result" or "expected error" for a given test case. - * @param testFuncAsync a test function which, e.g., makes a call or sends a - * transaction to a contract. It accepts the same N arguments returns the - * "actual result" or "actual error" for a given test case. - * @param values an array of N arrays. Each inner array is a set of possible - * values which are passed into both the reference function and the test - * function. - * @return A Promise that resolves if the test passes and rejects if the test - * fails, according to the rules described above. - */ -export async function testCombinatoriallyWithReferenceFuncAsync( - name: string, - referenceFuncAsync: (...args: any[]) => Promise<any>, - testFuncAsync: (...args: any[]) => Promise<any>, - allValues: any[], -): Promise<void> { - const testCases = combinatorics.cartesianProduct(...allValues); - let counter = 0; - testCases.forEach(async testCase => { - counter += 1; - it(`${name} ${counter}/${testCases.length}`, async () => { - await testWithReferenceFuncAsync(referenceFuncAsync, testFuncAsync, testCase as any); - }); - }); -} diff --git a/contracts/core/test/utils/constants.ts b/contracts/core/test/utils/constants.ts deleted file mode 100644 index d2c3ab512..000000000 --- a/contracts/core/test/utils/constants.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { BigNumber } from '@0x/utils'; -import { Web3Wrapper } from '@0x/web3-wrapper'; -import * as ethUtil from 'ethereumjs-util'; -import * as _ from 'lodash'; - -const TESTRPC_PRIVATE_KEYS_STRINGS = [ - '0xf2f48ee19680706196e2e339e5da3491186e0c4c5030670656b0e0164837257d', - '0x5d862464fe9303452126c8bc94274b8c5f9874cbd219789b3eb2128075a76f72', - '0xdf02719c4df8b9b8ac7f551fcb5d9ef48fa27eef7a66453879f4d8fdc6e78fb1', - '0xff12e391b79415e941a94de3bf3a9aee577aed0731e297d5cfa0b8a1e02fa1d0', - '0x752dd9cf65e68cfaba7d60225cbdbc1f4729dd5e5507def72815ed0d8abc6249', - '0xefb595a0178eb79a8df953f87c5148402a224cdf725e88c0146727c6aceadccd', - '0x83c6d2cc5ddcf9711a6d59b417dc20eb48afd58d45290099e5987e3d768f328f', - '0xbb2d3f7c9583780a7d3904a2f55d792707c345f21de1bacb2d389934d82796b2', - '0xb2fd4d29c1390b71b8795ae81196bfd60293adf99f9d32a0aff06288fcdac55f', - '0x23cb7121166b9a2f93ae0b7c05bde02eae50d64449b2cbb42bc84e9d38d6cc89', -]; - -export const constants = { - BASE_16: 16, - INVALID_OPCODE: 'invalid opcode', - TESTRPC_NETWORK_ID: 50, - // Note(albrow): In practice V8 and most other engines limit the minimum - // interval for setInterval to 10ms. We still set it to 0 here in order to - // ensure we always use the minimum interval. - AWAIT_TRANSACTION_MINED_MS: 0, - MAX_ETHERTOKEN_WITHDRAW_GAS: 43000, - MAX_EXECUTE_TRANSACTION_GAS: 1000000, - MAX_TOKEN_TRANSFERFROM_GAS: 80000, - MAX_TOKEN_APPROVE_GAS: 60000, - MAX_TRANSFER_FROM_GAS: 150000, - DUMMY_TOKEN_NAME: '', - DUMMY_TOKEN_SYMBOL: '', - DUMMY_TOKEN_DECIMALS: new BigNumber(18), - DUMMY_TOKEN_TOTAL_SUPPLY: new BigNumber(0), - NULL_BYTES: '0x', - NUM_DUMMY_ERC20_TO_DEPLOY: 3, - NUM_DUMMY_ERC721_TO_DEPLOY: 2, - NUM_ERC721_TOKENS_TO_MINT: 2, - NULL_ADDRESS: '0x0000000000000000000000000000000000000000', - UNLIMITED_ALLOWANCE_IN_BASE_UNITS: new BigNumber(2).pow(256).minus(1), - TESTRPC_PRIVATE_KEYS: _.map(TESTRPC_PRIVATE_KEYS_STRINGS, privateKeyString => ethUtil.toBuffer(privateKeyString)), - INITIAL_ERC20_BALANCE: Web3Wrapper.toBaseUnitAmount(new BigNumber(10000), 18), - INITIAL_ERC20_ALLOWANCE: Web3Wrapper.toBaseUnitAmount(new BigNumber(10000), 18), - STATIC_ORDER_PARAMS: { - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(200), 18), - makerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 18), - takerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 18), - }, - WORD_LENGTH: 32, - ZERO_AMOUNT: new BigNumber(0), - PERCENTAGE_DENOMINATOR: new BigNumber(10).pow(18), - FUNCTIONS_WITH_MUTEX: [ - 'FILL_ORDER', - 'FILL_OR_KILL_ORDER', - 'BATCH_FILL_ORDERS', - 'BATCH_FILL_OR_KILL_ORDERS', - 'MARKET_BUY_ORDERS', - 'MARKET_SELL_ORDERS', - 'MATCH_ORDERS', - 'CANCEL_ORDER', - 'BATCH_CANCEL_ORDERS', - 'CANCEL_ORDERS_UP_TO', - 'SET_SIGNATURE_VALIDATOR_APPROVAL', - ], -}; diff --git a/contracts/core/test/utils/coverage.ts b/contracts/core/test/utils/coverage.ts deleted file mode 100644 index 5becfa1b6..000000000 --- a/contracts/core/test/utils/coverage.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { devConstants } from '@0x/dev-utils'; -import { CoverageSubprovider, SolCompilerArtifactAdapter } from '@0x/sol-cov'; -import * as _ from 'lodash'; - -let coverageSubprovider: CoverageSubprovider; - -export const coverage = { - getCoverageSubproviderSingleton(): CoverageSubprovider { - if (_.isUndefined(coverageSubprovider)) { - coverageSubprovider = coverage._getCoverageSubprovider(); - } - return coverageSubprovider; - }, - _getCoverageSubprovider(): CoverageSubprovider { - const defaultFromAddress = devConstants.TESTRPC_FIRST_ADDRESS; - const solCompilerArtifactAdapter = new SolCompilerArtifactAdapter(); - const isVerbose = true; - const subprovider = new CoverageSubprovider(solCompilerArtifactAdapter, defaultFromAddress, isVerbose); - return subprovider; - }, -}; diff --git a/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..5d0ea07a8 100644 --- a/contracts/core/test/utils/fill_order_combinatorial_utils.ts +++ b/contracts/core/test/utils/fill_order_combinatorial_utils.ts @@ -1,3 +1,21 @@ +import { artifacts as libsArtifacts, TestLibsContract } from '@0x/contracts-libs'; +import { + AllowanceAmountScenario, + AssetDataScenario, + BalanceAmountScenario, + chaiSetup, + constants, + expectTransactionFailedAsync, + ExpirationTimeSecondsScenario, + FeeRecipientAddressScenario, + FillScenario, + OrderAssetAmountScenario, + orderUtils, + signingUtils, + TakerAssetFillAmountScenario, + TakerScenario, + TraderStateScenario, +} from '@0x/contracts-test-utils'; import { assetDataUtils, BalanceAndProxyAllowanceLazyStore, @@ -15,33 +33,15 @@ import * as _ from 'lodash'; import 'make-promises-safe'; import { ExchangeContract, ExchangeFillEventArgs } from '../../generated-wrappers/exchange'; -import { TestLibsContract } from '../../generated-wrappers/test_libs'; import { artifacts } from '../../src/artifacts'; -import { expectTransactionFailedAsync } from './assertions'; import { AssetWrapper } from './asset_wrapper'; -import { chaiSetup } from './chai_setup'; -import { constants } from './constants'; import { ERC20Wrapper } from './erc20_wrapper'; import { ERC721Wrapper } from './erc721_wrapper'; import { ExchangeWrapper } from './exchange_wrapper'; import { OrderFactoryFromScenario } from './order_factory_from_scenario'; -import { orderUtils } from './order_utils'; -import { signingUtils } from './signing_utils'; import { SimpleAssetBalanceAndProxyAllowanceFetcher } from './simple_asset_balance_and_proxy_allowance_fetcher'; import { SimpleOrderFilledCancelledFetcher } from './simple_order_filled_cancelled_fetcher'; -import { - AllowanceAmountScenario, - AssetDataScenario, - BalanceAmountScenario, - ExpirationTimeSecondsScenario, - FeeRecipientAddressScenario, - FillScenario, - OrderAssetAmountScenario, - TakerAssetFillAmountScenario, - TakerScenario, - TraderStateScenario, -} from './types'; chaiSetup.configure(); const expect = chai.expect; @@ -131,7 +131,11 @@ export async function fillOrderCombinatorialUtilsFactoryAsync( exchangeContract.address, ); - const testLibsContract = await TestLibsContract.deployFrom0xArtifactAsync(artifacts.TestLibs, provider, txDefaults); + const testLibsContract = await TestLibsContract.deployFrom0xArtifactAsync( + libsArtifacts.TestLibs, + provider, + txDefaults, + ); const fillOrderCombinatorialUtils = new FillOrderCombinatorialUtils( orderFactory, diff --git a/contracts/core/test/utils/formatters.ts b/contracts/core/test/utils/formatters.ts deleted file mode 100644 index 813eb45db..000000000 --- a/contracts/core/test/utils/formatters.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { SignedOrder } from '@0x/types'; -import { BigNumber } from '@0x/utils'; -import * as _ from 'lodash'; - -import { constants } from './constants'; -import { orderUtils } from './order_utils'; -import { BatchCancelOrders, BatchFillOrders, MarketBuyOrders, MarketSellOrders } from './types'; - -export const formatters = { - createBatchFill(signedOrders: SignedOrder[], takerAssetFillAmounts: BigNumber[] = []): BatchFillOrders { - const batchFill: BatchFillOrders = { - orders: [], - signatures: [], - takerAssetFillAmounts, - }; - _.forEach(signedOrders, signedOrder => { - const orderWithoutExchangeAddress = orderUtils.getOrderWithoutExchangeAddress(signedOrder); - batchFill.orders.push(orderWithoutExchangeAddress); - batchFill.signatures.push(signedOrder.signature); - if (takerAssetFillAmounts.length < signedOrders.length) { - batchFill.takerAssetFillAmounts.push(signedOrder.takerAssetAmount); - } - }); - return batchFill; - }, - createMarketSellOrders(signedOrders: SignedOrder[], takerAssetFillAmount: BigNumber): MarketSellOrders { - const marketSellOrders: MarketSellOrders = { - orders: [], - signatures: [], - takerAssetFillAmount, - }; - _.forEach(signedOrders, (signedOrder, i) => { - const orderWithoutExchangeAddress = orderUtils.getOrderWithoutExchangeAddress(signedOrder); - if (i !== 0) { - orderWithoutExchangeAddress.takerAssetData = constants.NULL_BYTES; - } - marketSellOrders.orders.push(orderWithoutExchangeAddress); - marketSellOrders.signatures.push(signedOrder.signature); - }); - return marketSellOrders; - }, - createMarketBuyOrders(signedOrders: SignedOrder[], makerAssetFillAmount: BigNumber): MarketBuyOrders { - const marketBuyOrders: MarketBuyOrders = { - orders: [], - signatures: [], - makerAssetFillAmount, - }; - _.forEach(signedOrders, (signedOrder, i) => { - const orderWithoutExchangeAddress = orderUtils.getOrderWithoutExchangeAddress(signedOrder); - if (i !== 0) { - orderWithoutExchangeAddress.makerAssetData = constants.NULL_BYTES; - } - marketBuyOrders.orders.push(orderWithoutExchangeAddress); - marketBuyOrders.signatures.push(signedOrder.signature); - }); - return marketBuyOrders; - }, - createBatchCancel(signedOrders: SignedOrder[]): BatchCancelOrders { - const batchCancel: BatchCancelOrders = { - orders: [], - }; - _.forEach(signedOrders, signedOrder => { - const orderWithoutExchangeAddress = orderUtils.getOrderWithoutExchangeAddress(signedOrder); - batchCancel.orders.push(orderWithoutExchangeAddress); - }); - return batchCancel; - }, -}; diff --git a/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/log_decoder.ts b/contracts/core/test/utils/log_decoder.ts deleted file mode 100644 index 05b0a9204..000000000 --- a/contracts/core/test/utils/log_decoder.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { AbiDecoder, BigNumber } from '@0x/utils'; -import { Web3Wrapper } from '@0x/web3-wrapper'; -import { - AbiDefinition, - ContractArtifact, - DecodedLogArgs, - LogEntry, - LogWithDecodedArgs, - RawLog, - TransactionReceiptWithDecodedLogs, -} from 'ethereum-types'; -import * as _ from 'lodash'; - -import { artifacts } from '../../src/artifacts'; - -import { constants } from './constants'; - -export class LogDecoder { - private readonly _web3Wrapper: Web3Wrapper; - private readonly _abiDecoder: AbiDecoder; - public static wrapLogBigNumbers(log: any): any { - const argNames = _.keys(log.args); - for (const argName of argNames) { - const isWeb3BigNumber = _.startsWith(log.args[argName].constructor.toString(), 'function BigNumber('); - if (isWeb3BigNumber) { - log.args[argName] = new BigNumber(log.args[argName]); - } - } - } - constructor(web3Wrapper: Web3Wrapper) { - this._web3Wrapper = web3Wrapper; - const abiArrays: AbiDefinition[][] = []; - _.forEach(artifacts, (artifact: ContractArtifact) => { - const compilerOutput = artifact.compilerOutput; - abiArrays.push(compilerOutput.abi); - }); - this._abiDecoder = new AbiDecoder(abiArrays); - } - public decodeLogOrThrow<ArgsType extends DecodedLogArgs>(log: LogEntry): LogWithDecodedArgs<ArgsType> | RawLog { - const logWithDecodedArgsOrLog = this._abiDecoder.tryToDecodeLogOrNoop(log); - // tslint:disable-next-line:no-unnecessary-type-assertion - if (_.isUndefined((logWithDecodedArgsOrLog as LogWithDecodedArgs<ArgsType>).args)) { - throw new Error(`Unable to decode log: ${JSON.stringify(log)}`); - } - LogDecoder.wrapLogBigNumbers(logWithDecodedArgsOrLog); - return logWithDecodedArgsOrLog; - } - public async getTxWithDecodedLogsAsync(txHash: string): Promise<TransactionReceiptWithDecodedLogs> { - const tx = await this._web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); - tx.logs = _.map(tx.logs, log => this.decodeLogOrThrow(log)); - return tx; - } -} diff --git a/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.ts b/contracts/core/test/utils/order_factory.ts deleted file mode 100644 index 2449d1a8a..000000000 --- a/contracts/core/test/utils/order_factory.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { generatePseudoRandomSalt, orderHashUtils } from '@0x/order-utils'; -import { Order, SignatureType, SignedOrder } from '@0x/types'; -import { BigNumber } from '@0x/utils'; - -import { getLatestBlockTimestampAsync } from './block_timestamp'; -import { constants } from './constants'; -import { signingUtils } from './signing_utils'; - -export class OrderFactory { - private readonly _defaultOrderParams: Partial<Order>; - private readonly _privateKey: Buffer; - constructor(privateKey: Buffer, defaultOrderParams: Partial<Order>) { - this._defaultOrderParams = defaultOrderParams; - this._privateKey = privateKey; - } - public async newSignedOrderAsync( - customOrderParams: Partial<Order> = {}, - signatureType: SignatureType = SignatureType.EthSign, - ): Promise<SignedOrder> { - const tenMinutesInSeconds = 10 * 60; - const currentBlockTimestamp = await getLatestBlockTimestampAsync(); - const order = ({ - senderAddress: constants.NULL_ADDRESS, - expirationTimeSeconds: new BigNumber(currentBlockTimestamp).add(tenMinutesInSeconds), - salt: generatePseudoRandomSalt(), - takerAddress: constants.NULL_ADDRESS, - ...this._defaultOrderParams, - ...customOrderParams, - } as any) as Order; - const orderHashBuff = orderHashUtils.getOrderHashBuffer(order); - const signature = signingUtils.signMessage(orderHashBuff, this._privateKey, signatureType); - const signedOrder = { - ...order, - signature: `0x${signature.toString('hex')}`, - }; - return signedOrder; - } -} diff --git a/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/test/utils/order_utils.ts b/contracts/core/test/utils/order_utils.ts deleted file mode 100644 index 4f7a34011..000000000 --- a/contracts/core/test/utils/order_utils.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { OrderWithoutExchangeAddress, SignedOrder } from '@0x/types'; -import { BigNumber } from '@0x/utils'; - -import { constants } from './constants'; -import { CancelOrder, MatchOrder } from './types'; - -export const orderUtils = { - getPartialAmountFloor(numerator: BigNumber, denominator: BigNumber, target: BigNumber): BigNumber { - const partialAmount = numerator - .mul(target) - .div(denominator) - .floor(); - return partialAmount; - }, - createFill: (signedOrder: SignedOrder, takerAssetFillAmount?: BigNumber) => { - const fill = { - order: orderUtils.getOrderWithoutExchangeAddress(signedOrder), - takerAssetFillAmount: takerAssetFillAmount || signedOrder.takerAssetAmount, - signature: signedOrder.signature, - }; - return fill; - }, - createCancel(signedOrder: SignedOrder, takerAssetCancelAmount?: BigNumber): CancelOrder { - const cancel = { - order: orderUtils.getOrderWithoutExchangeAddress(signedOrder), - takerAssetCancelAmount: takerAssetCancelAmount || signedOrder.takerAssetAmount, - }; - return cancel; - }, - getOrderWithoutExchangeAddress(signedOrder: SignedOrder): OrderWithoutExchangeAddress { - const orderStruct = { - senderAddress: signedOrder.senderAddress, - makerAddress: signedOrder.makerAddress, - takerAddress: signedOrder.takerAddress, - feeRecipientAddress: signedOrder.feeRecipientAddress, - makerAssetAmount: signedOrder.makerAssetAmount, - takerAssetAmount: signedOrder.takerAssetAmount, - makerFee: signedOrder.makerFee, - takerFee: signedOrder.takerFee, - expirationTimeSeconds: signedOrder.expirationTimeSeconds, - salt: signedOrder.salt, - makerAssetData: signedOrder.makerAssetData, - takerAssetData: signedOrder.takerAssetData, - }; - return orderStruct; - }, - createMatchOrders(signedOrderLeft: SignedOrder, signedOrderRight: SignedOrder): MatchOrder { - const fill = { - left: orderUtils.getOrderWithoutExchangeAddress(signedOrderLeft), - right: orderUtils.getOrderWithoutExchangeAddress(signedOrderRight), - leftSignature: signedOrderLeft.signature, - rightSignature: signedOrderRight.signature, - }; - fill.right.makerAssetData = constants.NULL_BYTES; - fill.right.takerAssetData = constants.NULL_BYTES; - return fill; - }, -}; diff --git a/contracts/core/test/utils/profiler.ts b/contracts/core/test/utils/profiler.ts deleted file mode 100644 index 2c7c1d66c..000000000 --- a/contracts/core/test/utils/profiler.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { devConstants } from '@0x/dev-utils'; -import { ProfilerSubprovider, SolCompilerArtifactAdapter } from '@0x/sol-cov'; -import * as _ from 'lodash'; - -let profilerSubprovider: ProfilerSubprovider; - -export const profiler = { - start(): void { - profiler.getProfilerSubproviderSingleton().start(); - }, - stop(): void { - profiler.getProfilerSubproviderSingleton().stop(); - }, - getProfilerSubproviderSingleton(): ProfilerSubprovider { - if (_.isUndefined(profilerSubprovider)) { - profilerSubprovider = profiler._getProfilerSubprovider(); - } - return profilerSubprovider; - }, - _getProfilerSubprovider(): ProfilerSubprovider { - const defaultFromAddress = devConstants.TESTRPC_FIRST_ADDRESS; - const solCompilerArtifactAdapter = new SolCompilerArtifactAdapter(); - const isVerbose = true; - const subprovider = new ProfilerSubprovider(solCompilerArtifactAdapter, defaultFromAddress, isVerbose); - return subprovider; - }, -}; diff --git a/contracts/core/test/utils/revert_trace.ts b/contracts/core/test/utils/revert_trace.ts deleted file mode 100644 index 3f74fd28b..000000000 --- a/contracts/core/test/utils/revert_trace.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { devConstants } from '@0x/dev-utils'; -import { RevertTraceSubprovider, SolCompilerArtifactAdapter } from '@0x/sol-cov'; -import * as _ from 'lodash'; - -let revertTraceSubprovider: RevertTraceSubprovider; - -export const revertTrace = { - getRevertTraceSubproviderSingleton(): RevertTraceSubprovider { - if (_.isUndefined(revertTraceSubprovider)) { - revertTraceSubprovider = revertTrace._getRevertTraceSubprovider(); - } - return revertTraceSubprovider; - }, - _getRevertTraceSubprovider(): RevertTraceSubprovider { - const defaultFromAddress = devConstants.TESTRPC_FIRST_ADDRESS; - const solCompilerArtifactAdapter = new SolCompilerArtifactAdapter(); - const isVerbose = true; - const subprovider = new RevertTraceSubprovider(solCompilerArtifactAdapter, defaultFromAddress, isVerbose); - return subprovider; - }, -}; diff --git a/contracts/core/test/utils/signing_utils.ts b/contracts/core/test/utils/signing_utils.ts deleted file mode 100644 index 21f864bfa..000000000 --- a/contracts/core/test/utils/signing_utils.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { SignatureType } from '@0x/types'; -import * as ethUtil from 'ethereumjs-util'; - -export const signingUtils = { - signMessage(message: Buffer, privateKey: Buffer, signatureType: SignatureType): Buffer { - if (signatureType === SignatureType.EthSign) { - const prefixedMessage = ethUtil.hashPersonalMessage(message); - const ecSignature = ethUtil.ecsign(prefixedMessage, privateKey); - const signature = Buffer.concat([ - ethUtil.toBuffer(ecSignature.v), - ecSignature.r, - ecSignature.s, - ethUtil.toBuffer(signatureType), - ]); - return signature; - } else if (signatureType === SignatureType.EIP712) { - const ecSignature = ethUtil.ecsign(message, privateKey); - const signature = Buffer.concat([ - ethUtil.toBuffer(ecSignature.v), - ecSignature.r, - ecSignature.s, - ethUtil.toBuffer(signatureType), - ]); - return signature; - } else { - throw new Error(`${signatureType} is not a valid signature type`); - } - }, -}; diff --git a/contracts/core/test/utils/test_with_reference.ts b/contracts/core/test/utils/test_with_reference.ts deleted file mode 100644 index b80be4a6c..000000000 --- a/contracts/core/test/utils/test_with_reference.ts +++ /dev/null @@ -1,139 +0,0 @@ -import * as chai from 'chai'; -import * as _ from 'lodash'; - -import { chaiSetup } from './chai_setup'; - -chaiSetup.configure(); -const expect = chai.expect; - -class Value<T> { - public value: T; - constructor(value: T) { - this.value = value; - } -} - -// tslint:disable-next-line: max-classes-per-file -class ErrorMessage { - public error: string; - constructor(message: string) { - this.error = message; - } -} - -type PromiseResult<T> = Value<T> | ErrorMessage; - -// TODO(albrow): This seems like a generic utility function that could exist in -// lodash. We should replace it by a library implementation, or move it to our -// own. -async function evaluatePromise<T>(promise: Promise<T>): Promise<PromiseResult<T>> { - try { - return new Value<T>(await promise); - } catch (e) { - return new ErrorMessage(e.message); - } -} - -export async function testWithReferenceFuncAsync<P0, R>( - referenceFunc: (p0: P0) => Promise<R>, - testFunc: (p0: P0) => Promise<R>, - values: [P0], -): Promise<void>; -export async function testWithReferenceFuncAsync<P0, P1, R>( - referenceFunc: (p0: P0, p1: P1) => Promise<R>, - testFunc: (p0: P0, p1: P1) => Promise<R>, - values: [P0, P1], -): Promise<void>; -export async function testWithReferenceFuncAsync<P0, P1, P2, R>( - referenceFunc: (p0: P0, p1: P1, p2: P2) => Promise<R>, - testFunc: (p0: P0, p1: P1, p2: P2) => Promise<R>, - values: [P0, P1, P2], -): Promise<void>; -export async function testWithReferenceFuncAsync<P0, P1, P2, P3, R>( - referenceFunc: (p0: P0, p1: P1, p2: P2, p3: P3) => Promise<R>, - testFunc: (p0: P0, p1: P1, p2: P2, p3: P3) => Promise<R>, - values: [P0, P1, P2, P3], -): Promise<void>; -export async function testWithReferenceFuncAsync<P0, P1, P2, P3, P4, R>( - referenceFunc: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4) => Promise<R>, - testFunc: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4) => Promise<R>, - values: [P0, P1, P2, P3, P4], -): Promise<void>; - -/** - * Tests the behavior of a test function by comparing it to the expected - * behavior (defined by a reference function). - * - * First the reference function will be called to obtain an "expected result", - * or if the reference function throws/rejects, an "expected error". Next, the - * test function will be called to obtain an "actual result", or if the test - * function throws/rejects, an "actual error". The test passes if at least one - * of the following conditions is met: - * - * 1) Neither the reference function or the test function throw and the - * "expected result" equals the "actual result". - * - * 2) Both the reference function and the test function throw and the "actual - * error" message *contains* the "expected error" message. - * - * @param referenceFuncAsync a reference function implemented in pure - * JavaScript/TypeScript which accepts N arguments and returns the "expected - * result" or throws/rejects with the "expected error". - * @param testFuncAsync a test function which, e.g., makes a call or sends a - * transaction to a contract. It accepts the same N arguments returns the - * "actual result" or throws/rejects with the "actual error". - * @param values an array of N values, where each value corresponds in-order to - * an argument to both the test function and the reference function. - * @return A Promise that resolves if the test passes and rejects if the test - * fails, according to the rules described above. - */ -export async function testWithReferenceFuncAsync( - referenceFuncAsync: (...args: any[]) => Promise<any>, - testFuncAsync: (...args: any[]) => Promise<any>, - values: any[], -): Promise<void> { - // Measure correct behaviour - const expected = await evaluatePromise(referenceFuncAsync(...values)); - - // Measure actual behaviour - const actual = await evaluatePromise(testFuncAsync(...values)); - - // Compare behaviour - if (expected instanceof ErrorMessage) { - // If we expected an error, check if the actual error message contains the - // expected error message. - if (!(actual instanceof ErrorMessage)) { - throw new Error( - `Expected error containing ${expected.error} but got no error\n\tTest case: ${_getTestCaseString( - referenceFuncAsync, - values, - )}`, - ); - } - expect(actual.error).to.contain( - expected.error, - `${actual.error}\n\tTest case: ${_getTestCaseString(referenceFuncAsync, values)}`, - ); - } else { - // If we do not expect an error, compare actual and expected directly. - expect(actual).to.deep.equal(expected, `Test case ${_getTestCaseString(referenceFuncAsync, values)}`); - } -} - -function _getTestCaseString(referenceFuncAsync: (...args: any[]) => Promise<any>, values: any[]): string { - const paramNames = _getParameterNames(referenceFuncAsync); - return JSON.stringify(_.zipObject(paramNames, values)); -} - -// Source: https://stackoverflow.com/questions/1007981/how-to-get-function-parameter-names-values-dynamically -function _getParameterNames(func: (...args: any[]) => any): string[] { - return _.toString(func) - .replace(/[/][/].*$/gm, '') // strip single-line comments - .replace(/\s+/g, '') // strip white space - .replace(/[/][*][^/*]*[*][/]/g, '') // strip multi-line comments - .split('){', 1)[0] - .replace(/^[^(]*[(]/, '') // extract the parameters - .replace(/=[^,]+/g, '') // strip any ES6 defaults - .split(',') - .filter(Boolean); // split & filter [""] -} diff --git a/contracts/core/test/utils/transaction_factory.ts b/contracts/core/test/utils/transaction_factory.ts deleted file mode 100644 index dbab3ade4..000000000 --- a/contracts/core/test/utils/transaction_factory.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { eip712Utils, generatePseudoRandomSalt } from '@0x/order-utils'; -import { SignatureType } from '@0x/types'; -import { signTypedDataUtils } from '@0x/utils'; -import * as ethUtil from 'ethereumjs-util'; - -import { signingUtils } from './signing_utils'; -import { SignedTransaction } from './types'; - -export class TransactionFactory { - private readonly _signerBuff: Buffer; - private readonly _exchangeAddress: string; - private readonly _privateKey: Buffer; - constructor(privateKey: Buffer, exchangeAddress: string) { - this._privateKey = privateKey; - this._exchangeAddress = exchangeAddress; - this._signerBuff = ethUtil.privateToAddress(this._privateKey); - } - public newSignedTransaction(data: string, signatureType: SignatureType = SignatureType.EthSign): SignedTransaction { - const salt = generatePseudoRandomSalt(); - const signerAddress = `0x${this._signerBuff.toString('hex')}`; - const executeTransactionData = { - salt, - signerAddress, - data, - }; - - const typedData = eip712Utils.createZeroExTransactionTypedData(executeTransactionData, this._exchangeAddress); - const eip712MessageBuffer = signTypedDataUtils.generateTypedDataHash(typedData); - const signature = signingUtils.signMessage(eip712MessageBuffer, this._privateKey, signatureType); - const signedTx = { - exchangeAddress: this._exchangeAddress, - signature: `0x${signature.toString('hex')}`, - ...executeTransactionData, - }; - return signedTx; - } -} diff --git a/contracts/core/test/utils/type_encoding_utils.ts b/contracts/core/test/utils/type_encoding_utils.ts deleted file mode 100644 index bfd9c9ef5..000000000 --- a/contracts/core/test/utils/type_encoding_utils.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { BigNumber } from '@0x/utils'; -import BN = require('bn.js'); -import ethUtil = require('ethereumjs-util'); - -import { constants } from './constants'; - -export const typeEncodingUtils = { - encodeUint256(value: BigNumber): Buffer { - const base = 10; - const formattedValue = new BN(value.toString(base)); - const encodedValue = ethUtil.toBuffer(formattedValue); - // tslint:disable-next-line:custom-no-magic-numbers - const paddedValue = ethUtil.setLengthLeft(encodedValue, constants.WORD_LENGTH); - return paddedValue; - }, - decodeUint256(encodedValue: Buffer): BigNumber { - const formattedValue = ethUtil.bufferToHex(encodedValue); - const value = new BigNumber(formattedValue, constants.BASE_16); - return value; - }, -}; diff --git a/contracts/core/test/utils/types.ts b/contracts/core/test/utils/types.ts deleted file mode 100644 index d738fcd4e..000000000 --- a/contracts/core/test/utils/types.ts +++ /dev/null @@ -1,242 +0,0 @@ -import { OrderWithoutExchangeAddress } from '@0x/types'; -import { BigNumber } from '@0x/utils'; -import { AbiDefinition } from 'ethereum-types'; - -export interface ERC20BalancesByOwner { - [ownerAddress: string]: { - [tokenAddress: string]: BigNumber; - }; -} - -export interface ERC721TokenIdsByOwner { - [ownerAddress: string]: { - [tokenAddress: string]: BigNumber[]; - }; -} - -export interface SubmissionContractEventArgs { - transactionId: BigNumber; -} - -export interface BatchFillOrders { - orders: OrderWithoutExchangeAddress[]; - signatures: string[]; - takerAssetFillAmounts: BigNumber[]; -} - -export interface MarketSellOrders { - orders: OrderWithoutExchangeAddress[]; - signatures: string[]; - takerAssetFillAmount: BigNumber; -} - -export interface MarketBuyOrders { - orders: OrderWithoutExchangeAddress[]; - signatures: string[]; - makerAssetFillAmount: BigNumber; -} - -export interface BatchCancelOrders { - orders: OrderWithoutExchangeAddress[]; -} - -export interface CancelOrdersBefore { - salt: BigNumber; -} - -export interface TransactionDataParams { - name: string; - abi: AbiDefinition[]; - args: any[]; -} - -export interface MultiSigConfig { - owners: string[]; - confirmationsRequired: number; - secondsRequired: number; -} - -export interface MultiSigConfigByNetwork { - [networkName: string]: MultiSigConfig; -} - -export interface Token { - address?: string; - name: string; - symbol: string; - decimals: number; - ipfsHash: string; - swarmHash: string; -} - -export enum OrderStatus { - INVALID, - INVALID_MAKER_ASSET_AMOUNT, - INVALID_TAKER_ASSET_AMOUNT, - FILLABLE, - EXPIRED, - FULLY_FILLED, - CANCELLED, -} - -export enum ContractName { - TokenRegistry = 'TokenRegistry', - MultiSigWalletWithTimeLock = 'MultiSigWalletWithTimeLock', - Exchange = 'Exchange', - ZRXToken = 'ZRXToken', - DummyERC20Token = 'DummyERC20Token', - EtherToken = 'WETH9', - DutchAuction = 'DutchAuction', - AssetProxyOwner = 'AssetProxyOwner', - AccountLevels = 'AccountLevels', - EtherDelta = 'EtherDelta', - Arbitrage = 'Arbitrage', - TestAssetDataDecoders = 'TestAssetDataDecoders', - TestAssetProxyDispatcher = 'TestAssetProxyDispatcher', - TestLibs = 'TestLibs', - TestSignatureValidator = 'TestSignatureValidator', - ERC20Proxy = 'ERC20Proxy', - ERC721Proxy = 'ERC721Proxy', - DummyERC721Receiver = 'DummyERC721Receiver', - DummyERC721Token = 'DummyERC721Token', - TestLibBytes = 'TestLibBytes', - TestWallet = 'TestWallet', - Authorizable = 'Authorizable', - Whitelist = 'Whitelist', - Forwarder = 'Forwarder', -} - -export interface SignedTransaction { - exchangeAddress: string; - salt: BigNumber; - signerAddress: string; - data: string; - signature: string; -} - -export interface TransferAmountsByMatchOrders { - // Left Maker - amountBoughtByLeftMaker: BigNumber; - amountSoldByLeftMaker: BigNumber; - feePaidByLeftMaker: BigNumber; - // Right Maker - amountBoughtByRightMaker: BigNumber; - amountSoldByRightMaker: BigNumber; - feePaidByRightMaker: BigNumber; - // Taker - amountReceivedByTaker: BigNumber; - feePaidByTakerLeft: BigNumber; - feePaidByTakerRight: BigNumber; -} - -export interface TransferAmountsLoggedByMatchOrders { - makerAddress: string; - takerAddress: string; - makerAssetFilledAmount: string; - takerAssetFilledAmount: string; - makerFeePaid: string; - takerFeePaid: string; -} - -export interface OrderInfo { - orderStatus: number; - orderHash: string; - orderTakerAssetFilledAmount: BigNumber; -} - -export interface CancelOrder { - order: OrderWithoutExchangeAddress; - takerAssetCancelAmount: BigNumber; -} - -export interface MatchOrder { - left: OrderWithoutExchangeAddress; - right: OrderWithoutExchangeAddress; - leftSignature: string; - rightSignature: string; -} - -// Combinatorial testing types - -export enum FeeRecipientAddressScenario { - BurnAddress = 'BURN_ADDRESS', - EthUserAddress = 'ETH_USER_ADDRESS', -} - -export enum OrderAssetAmountScenario { - Zero = 'ZERO', - Large = 'LARGE', - Small = 'SMALL', -} - -export enum TakerScenario { - CorrectlySpecified = 'CORRECTLY_SPECIFIED', - IncorrectlySpecified = 'INCORRECTLY_SPECIFIED', - Unspecified = 'UNSPECIFIED', -} - -export enum ExpirationTimeSecondsScenario { - InPast = 'IN_PAST', - InFuture = 'IN_FUTURE', -} - -export enum AssetDataScenario { - ERC20ZeroDecimals = 'ERC20_ZERO_DECIMALS', - ZRXFeeToken = 'ZRX_FEE_TOKEN', - ERC20FiveDecimals = 'ERC20_FIVE_DECIMALS', - ERC20NonZRXEighteenDecimals = 'ERC20_NON_ZRX_EIGHTEEN_DECIMALS', - ERC721 = 'ERC721', -} - -export enum TakerAssetFillAmountScenario { - Zero = 'ZERO', - GreaterThanRemainingFillableTakerAssetAmount = 'GREATER_THAN_REMAINING_FILLABLE_TAKER_ASSET_AMOUNT', - LessThanRemainingFillableTakerAssetAmount = 'LESS_THAN_REMAINING_FILLABLE_TAKER_ASSET_AMOUNT', - ExactlyRemainingFillableTakerAssetAmount = 'EXACTLY_REMAINING_FILLABLE_TAKER_ASSET_AMOUNT', -} - -export interface OrderScenario { - takerScenario: TakerScenario; - feeRecipientScenario: FeeRecipientAddressScenario; - makerAssetAmountScenario: OrderAssetAmountScenario; - takerAssetAmountScenario: OrderAssetAmountScenario; - makerFeeScenario: OrderAssetAmountScenario; - takerFeeScenario: OrderAssetAmountScenario; - expirationTimeSecondsScenario: ExpirationTimeSecondsScenario; - makerAssetDataScenario: AssetDataScenario; - takerAssetDataScenario: AssetDataScenario; -} - -export enum BalanceAmountScenario { - Exact = 'EXACT', - TooLow = 'TOO_LOW', - Higher = 'HIGHER', -} - -export enum AllowanceAmountScenario { - Exact = 'EXACT', - TooLow = 'TOO_LOW', - Higher = 'HIGHER', - Unlimited = 'UNLIMITED', -} - -export interface TraderStateScenario { - traderAssetBalance: BalanceAmountScenario; - traderAssetAllowance: AllowanceAmountScenario; - zrxFeeBalance: BalanceAmountScenario; - zrxFeeAllowance: AllowanceAmountScenario; -} - -export interface FillScenario { - orderScenario: OrderScenario; - takerAssetFillAmountScenario: TakerAssetFillAmountScenario; - makerStateScenario: TraderStateScenario; - takerStateScenario: TraderStateScenario; -} - -export interface FillResults { - makerAssetFilledAmount: BigNumber; - takerAssetFilledAmount: BigNumber; - makerFeePaid: BigNumber; - takerFeePaid: BigNumber; -} diff --git a/contracts/core/test/utils/web3_wrapper.ts b/contracts/core/test/utils/web3_wrapper.ts deleted file mode 100644 index f7b1a732a..000000000 --- a/contracts/core/test/utils/web3_wrapper.ts +++ /dev/null @@ -1,84 +0,0 @@ -import { devConstants, env, EnvVars, web3Factory } from '@0x/dev-utils'; -import { prependSubprovider, Web3ProviderEngine } from '@0x/subproviders'; -import { logUtils } from '@0x/utils'; -import { Web3Wrapper } from '@0x/web3-wrapper'; -import * as _ from 'lodash'; - -import { coverage } from './coverage'; -import { profiler } from './profiler'; -import { revertTrace } from './revert_trace'; - -enum ProviderType { - Ganache = 'ganache', - Geth = 'geth', -} - -let testProvider: ProviderType; -switch (process.env.TEST_PROVIDER) { - case undefined: - testProvider = ProviderType.Ganache; - break; - case 'ganache': - testProvider = ProviderType.Ganache; - break; - case 'geth': - testProvider = ProviderType.Geth; - break; - default: - throw new Error(`Unknown TEST_PROVIDER: ${process.env.TEST_PROVIDER}`); -} - -const ganacheTxDefaults = { - from: devConstants.TESTRPC_FIRST_ADDRESS, - gas: devConstants.GAS_LIMIT, -}; -const gethTxDefaults = { - from: devConstants.TESTRPC_FIRST_ADDRESS, -}; -export const txDefaults = testProvider === ProviderType.Ganache ? ganacheTxDefaults : gethTxDefaults; - -const gethConfigs = { - shouldUseInProcessGanache: false, - rpcUrl: 'http://localhost:8501', - shouldUseFakeGasEstimate: false, -}; -const ganacheConfigs = { - shouldUseInProcessGanache: true, -}; -const providerConfigs = testProvider === ProviderType.Ganache ? ganacheConfigs : gethConfigs; - -export const provider: Web3ProviderEngine = web3Factory.getRpcProvider(providerConfigs); -const isCoverageEnabled = env.parseBoolean(EnvVars.SolidityCoverage); -const isProfilerEnabled = env.parseBoolean(EnvVars.SolidityProfiler); -const isRevertTraceEnabled = env.parseBoolean(EnvVars.SolidityRevertTrace); -const enabledSubproviderCount = _.filter( - [isCoverageEnabled, isProfilerEnabled, isRevertTraceEnabled], - _.identity.bind(_), -).length; -if (enabledSubproviderCount > 1) { - throw new Error(`Only one of coverage, profiler, or revert trace subproviders can be enabled at a time`); -} -if (isCoverageEnabled) { - const coverageSubprovider = coverage.getCoverageSubproviderSingleton(); - prependSubprovider(provider, coverageSubprovider); -} -if (isProfilerEnabled) { - if (testProvider === ProviderType.Ganache) { - logUtils.warn( - "Gas costs in Ganache traces are incorrect and we don't recommend using it for profiling. Please switch to Geth", - ); - process.exit(1); - } - const profilerSubprovider = profiler.getProfilerSubproviderSingleton(); - logUtils.log( - "By default profilerSubprovider is stopped so that you don't get noise from setup code. Don't forget to start it before the code you want to profile and stop it afterwards", - ); - profilerSubprovider.stop(); - prependSubprovider(provider, profilerSubprovider); -} -if (isRevertTraceEnabled) { - const revertTraceSubprovider = revertTrace.getRevertTraceSubproviderSingleton(); - prependSubprovider(provider, revertTraceSubprovider); -} - -export const web3Wrapper = new Web3Wrapper(provider); diff --git a/contracts/core/test/utils_test/test_with_reference.ts b/contracts/core/test/utils_test/test_with_reference.ts deleted file mode 100644 index 8d633cd1f..000000000 --- a/contracts/core/test/utils_test/test_with_reference.ts +++ /dev/null @@ -1,63 +0,0 @@ -import * as chai from 'chai'; - -import { chaiSetup } from '../utils/chai_setup'; -import { testWithReferenceFuncAsync } from '../utils/test_with_reference'; - -chaiSetup.configure(); -const expect = chai.expect; - -async function divAsync(x: number, y: number): Promise<number> { - if (y === 0) { - throw new Error('MathError: divide by zero'); - } - return x / y; -} - -// returns an async function that always returns the given value. -function alwaysValueFunc(value: number): (x: number, y: number) => Promise<number> { - return async (x: number, y: number) => value; -} - -// returns an async function which always throws/rejects with the given error -// message. -function alwaysFailFunc(errMessage: string): (x: number, y: number) => Promise<number> { - return async (x: number, y: number) => { - throw new Error(errMessage); - }; -} - -describe('testWithReferenceFuncAsync', () => { - it('passes when both succeed and actual === expected', async () => { - await testWithReferenceFuncAsync(alwaysValueFunc(0.5), divAsync, [1, 2]); - }); - - it('passes when both fail and actual error contains expected error', async () => { - await testWithReferenceFuncAsync(alwaysFailFunc('divide by zero'), divAsync, [1, 0]); - }); - - it('fails when both succeed and actual !== expected', async () => { - expect(testWithReferenceFuncAsync(alwaysValueFunc(3), divAsync, [1, 2])).to.be.rejectedWith( - 'Test case {"x":1,"y":2}: expected { value: 0.5 } to deeply equal { value: 3 }', - ); - }); - - it('fails when both fail and actual error does not contain expected error', async () => { - expect( - testWithReferenceFuncAsync(alwaysFailFunc('Unexpected math error'), divAsync, [1, 0]), - ).to.be.rejectedWith( - 'MathError: divide by zero\n\tTest case: {"x":1,"y":0}: expected \'MathError: divide by zero\' to include \'Unexpected math error\'', - ); - }); - - it('fails when referenceFunc succeeds and testFunc fails', async () => { - expect(testWithReferenceFuncAsync(alwaysValueFunc(0), divAsync, [1, 0])).to.be.rejectedWith( - 'Test case {"x":1,"y":0}: expected { error: \'MathError: divide by zero\' } to deeply equal { value: 0 }', - ); - }); - - it('fails when referenceFunc fails and testFunc succeeds', async () => { - expect(testWithReferenceFuncAsync(alwaysFailFunc('divide by zero'), divAsync, [1, 2])).to.be.rejectedWith( - 'Expected error containing divide by zero but got no error\n\tTest case: {"x":1,"y":2}', - ); - }); -}); diff --git a/contracts/core/tsconfig.json b/contracts/core/tsconfig.json index 23b069110..f2f3c4e97 100644 --- a/contracts/core/tsconfig.json +++ b/contracts/core/tsconfig.json @@ -28,16 +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", "./generated-artifacts/Validator.json", |