diff options
44 files changed, 909 insertions, 185 deletions
diff --git a/packages/contracts/contracts/Exchange.sol b/packages/contracts/contracts/Exchange.sol index 02deee967..a402e7ca5 100644 --- a/packages/contracts/contracts/Exchange.sol +++ b/packages/contracts/contracts/Exchange.sol @@ -16,11 +16,11 @@ */ -pragma solidity 0.4.11; +pragma solidity ^0.4.11; import "./TokenTransferProxy.sol"; -import "./base/Token.sol"; -import "./base/SafeMath.sol"; +import "./tokens/Token.sol"; +import "./utils/SafeMath.sol"; /// @title Exchange - Facilitates exchange of ERC20 tokens. /// @author Amir Bandeali - <amir@0xProject.com>, Will Warren - <will@0xProject.com> @@ -600,3 +600,4 @@ contract Exchange is SafeMath { return Token(token).allowance.gas(EXTERNAL_QUERY_GAS_LIMIT)(owner, TOKEN_TRANSFER_PROXY_CONTRACT); // Limit gas to prevent reentrancy } } + diff --git a/packages/contracts/contracts/TokenRegistry.sol b/packages/contracts/contracts/TokenRegistry.sol index d370f8cfe..d2570e71d 100644 --- a/packages/contracts/contracts/TokenRegistry.sol +++ b/packages/contracts/contracts/TokenRegistry.sol @@ -16,9 +16,9 @@ */ -pragma solidity 0.4.11; +pragma solidity ^0.4.11; -import "./base/Ownable.sol"; +import "./utils/Ownable.sol"; /// @title Token Registry - Stores metadata associated with ERC20 tokens. See ERC22 https://github.com/ethereum/EIPs/issues/22 /// @author Amir Bandeali - <amir@0xProject.com>, Will Warren - <will@0xProject.com> @@ -306,3 +306,4 @@ contract TokenRegistry is Ownable { return tokenAddresses; } } + diff --git a/packages/contracts/contracts/TokenTransferProxy.sol b/packages/contracts/contracts/TokenTransferProxy.sol index 23b0b9e6d..fd2358496 100644 --- a/packages/contracts/contracts/TokenTransferProxy.sol +++ b/packages/contracts/contracts/TokenTransferProxy.sol @@ -16,10 +16,10 @@ */ -pragma solidity 0.4.11; +pragma solidity ^0.4.11; -import "./base/Token.sol"; -import "./base/Ownable.sol"; +import "./tokens/Token.sol"; +import "./utils/Ownable.sol"; /// @title TokenTransferProxy - Transfers tokens on behalf of contracts that have been approved via decentralized governance. /// @author Amir Bandeali - <amir@0xProject.com>, Will Warren - <will@0xProject.com> @@ -113,3 +113,4 @@ contract TokenTransferProxy is Ownable { return authorities; } } + diff --git a/packages/contracts/contracts/base/SafeMath.sol b/packages/contracts/contracts/base/SafeMath.sol deleted file mode 100644 index fac674a20..000000000 --- a/packages/contracts/contracts/base/SafeMath.sol +++ /dev/null @@ -1,41 +0,0 @@ -pragma solidity 0.4.11; - -contract SafeMath { - function safeMul(uint a, uint b) internal constant returns (uint256) { - uint c = a * b; - assert(a == 0 || c / a == b); - return c; - } - - function safeDiv(uint a, uint b) internal constant returns (uint256) { - uint c = a / b; - return c; - } - - function safeSub(uint a, uint b) internal constant returns (uint256) { - assert(b <= a); - return a - b; - } - - function safeAdd(uint a, uint b) internal constant returns (uint256) { - uint c = a + b; - assert(c >= a); - return c; - } - - function max64(uint64 a, uint64 b) internal constant returns (uint64) { - return a >= b ? a : b; - } - - function min64(uint64 a, uint64 b) internal constant returns (uint64) { - return a < b ? a : b; - } - - function max256(uint256 a, uint256 b) internal constant returns (uint256) { - return a >= b ? a : b; - } - - function min256(uint256 a, uint256 b) internal constant returns (uint256) { - return a < b ? a : b; - } -} diff --git a/packages/contracts/contracts/base/MultiSigWallet.sol b/packages/contracts/contracts/multisig/MultiSigWallet.sol index 7531224ea..ae7ef06fd 100644 --- a/packages/contracts/contracts/base/MultiSigWallet.sol +++ b/packages/contracts/contracts/multisig/MultiSigWallet.sol @@ -1,4 +1,4 @@ -pragma solidity 0.4.11; +pragma solidity ^0.4.11; /// @title Multisignature wallet - Allows multiple parties to agree on transactions before execution. /// @author Stefan George - <stefan.george@consensys.net> @@ -363,3 +363,4 @@ contract MultiSigWallet { _transactionIds[i - from] = transactionIdsTemp[i]; } } + diff --git a/packages/contracts/contracts/MultiSigWalletWithTimeLock.sol b/packages/contracts/contracts/multisig/MultiSigWalletWithTimeLock.sol index 70123e6b6..62273eba3 100644 --- a/packages/contracts/contracts/MultiSigWalletWithTimeLock.sol +++ b/packages/contracts/contracts/multisig/MultiSigWalletWithTimeLock.sol @@ -16,9 +16,9 @@ */ -pragma solidity 0.4.11; +pragma solidity ^0.4.11; -import "./base/MultiSigWallet.sol"; +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> @@ -130,3 +130,4 @@ contract MultiSigWalletWithTimeLock is MultiSigWallet { ConfirmationTimeSet(transactionId, confirmationTime); } } + diff --git a/packages/contracts/contracts/MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress.sol b/packages/contracts/contracts/multisig/MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress.sol index 15fdb1d07..07beb9f5b 100644 --- a/packages/contracts/contracts/MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress.sol +++ b/packages/contracts/contracts/multisig/MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress.sol @@ -16,7 +16,7 @@ */ -pragma solidity 0.4.11; +pragma solidity ^0.4.11; import "./MultiSigWalletWithTimeLock.sol"; @@ -80,3 +80,4 @@ contract MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress is MultiSigWall return true; } } + diff --git a/packages/contracts/contracts/test/DummyToken.sol b/packages/contracts/contracts/test/DummyToken.sol index 414c17b2a..046af3059 100644 --- a/packages/contracts/contracts/test/DummyToken.sol +++ b/packages/contracts/contracts/test/DummyToken.sol @@ -1,7 +1,7 @@ -pragma solidity 0.4.11; +pragma solidity ^0.4.11; import "./Mintable.sol"; -import "./../base/Ownable.sol"; +import "./../utils/Ownable.sol"; contract DummyToken is Mintable, Ownable { string public name; @@ -21,7 +21,9 @@ contract DummyToken is Mintable, Ownable { balances[msg.sender] = _totalSupply; } - function setBalance(address _target, uint _value) onlyOwner { + function setBalance(address _target, uint _value) + onlyOwner + { uint currBalance = balanceOf(_target); if (_value < currBalance) { totalSupply = safeSub(totalSupply, safeSub(currBalance, _value)); @@ -31,3 +33,4 @@ contract DummyToken is Mintable, Ownable { balances[_target] = _value; } } + diff --git a/packages/contracts/contracts/test/DummyToken_v2.sol b/packages/contracts/contracts/test/DummyToken_v2.sol new file mode 100644 index 000000000..bd4d06be9 --- /dev/null +++ b/packages/contracts/contracts/test/DummyToken_v2.sol @@ -0,0 +1,38 @@ +pragma solidity 0.4.18; + +import "./Mintable_v2.sol"; +import "./../utils/Ownable_v2.sol"; + +contract DummyToken_v2 is Mintable_v2, Ownable_v2 { + string public name; + string public symbol; + uint public decimals; + + function DummyToken_v2( + string _name, + string _symbol, + uint _decimals, + uint _totalSupply) + public + { + name = _name; + symbol = _symbol; + decimals = _decimals; + totalSupply = _totalSupply; + balances[msg.sender] = _totalSupply; + } + + function setBalance(address _target, uint _value) + public + onlyOwner + { + uint currBalance = balanceOf(_target); + if (_value < currBalance) { + totalSupply = safeSub(totalSupply, safeSub(currBalance, _value)); + } else { + totalSupply = safeAdd(totalSupply, safeSub(_value, currBalance)); + } + balances[_target] = _value; + } +} + diff --git a/packages/contracts/contracts/test/MaliciousToken.sol b/packages/contracts/contracts/test/MaliciousToken.sol index 3c1a53612..3e7d5d1a5 100644 --- a/packages/contracts/contracts/test/MaliciousToken.sol +++ b/packages/contracts/contracts/test/MaliciousToken.sol @@ -1,11 +1,13 @@ -pragma solidity 0.4.11; +pragma solidity ^0.4.11; -import "./../base/StandardToken.sol"; +import "./../tokens/StandardToken.sol"; contract MaliciousToken is StandardToken { uint8 stateToUpdate = 1; // Not null so that change only requires 5000 gas - function updateState() internal { + function updateState() + internal + { stateToUpdate++; } @@ -27,3 +29,4 @@ contract MaliciousToken is StandardToken { return allowed[_owner][_spender]; } } + diff --git a/packages/contracts/contracts/test/Mintable.sol b/packages/contracts/contracts/test/Mintable.sol index c0438f304..3b91415ef 100644 --- a/packages/contracts/contracts/test/Mintable.sol +++ b/packages/contracts/contracts/test/Mintable.sol @@ -1,16 +1,19 @@ -pragma solidity 0.4.11; +pragma solidity ^0.4.11; import "./../tokens/UnlimitedAllowanceToken.sol"; -import "./../base/SafeMath.sol"; +import "./../utils/SafeMath.sol"; /* * Mintable * Base contract that creates a mintable UnlimitedAllowanceToken */ contract Mintable is UnlimitedAllowanceToken, SafeMath { - function mint(uint _value) { + function mint(uint _value) + public + { require(_value <= 100000000000000000000); balances[msg.sender] = safeAdd(_value, balances[msg.sender]); totalSupply = safeAdd(totalSupply, _value); } } + diff --git a/packages/contracts/contracts/test/Mintable_v2.sol b/packages/contracts/contracts/test/Mintable_v2.sol new file mode 100644 index 000000000..829145cfb --- /dev/null +++ b/packages/contracts/contracts/test/Mintable_v2.sol @@ -0,0 +1,19 @@ +pragma solidity 0.4.18; + +import "./../tokens/UnlimitedAllowanceToken_v2.sol"; +import "./../utils/SafeMath_v2.sol"; + +/* + * Mintable + * Base contract that creates a mintable UnlimitedAllowanceToken + */ +contract Mintable_v2 is UnlimitedAllowanceToken_v2, SafeMath_v2 { + function mint(uint _value) + public + { + require(_value <= 100000000000000000000); + balances[msg.sender] = safeAdd(_value, balances[msg.sender]); + totalSupply = safeAdd(totalSupply, _value); + } +} + diff --git a/packages/contracts/contracts/tokens/ERC20Token.sol b/packages/contracts/contracts/tokens/ERC20Token.sol new file mode 100644 index 000000000..318da8c01 --- /dev/null +++ b/packages/contracts/contracts/tokens/ERC20Token.sol @@ -0,0 +1,59 @@ +pragma solidity 0.4.18; + +import "./Token_v2.sol"; + +contract ERC20Token is Token_v2 { + + function transfer(address _to, uint _value) + public + returns (bool) + { + require(balances[msg.sender] >= _value && balances[_to] + _value >= balances[_to]); + balances[msg.sender] -= _value; + balances[_to] += _value; + Transfer(msg.sender, _to, _value); + return true; + } + + function transferFrom(address _from, address _to, uint _value) + public + returns (bool) + { + require(balances[_from] >= _value && allowed[_from][msg.sender] >= _value && balances[_to] + _value >= balances[_to]); + balances[_to] += _value; + balances[_from] -= _value; + allowed[_from][msg.sender] -= _value; + Transfer(_from, _to, _value); + return true; + } + + function approve(address _spender, uint _value) + public + returns (bool) + { + allowed[msg.sender][_spender] = _value; + Approval(msg.sender, _spender, _value); + return true; + } + + function balanceOf(address _owner) + public + view + returns (uint) + { + return balances[_owner]; + } + + function allowance(address _owner, address _spender) + public + view + returns (uint) + { + return allowed[_owner][_spender]; + } + + mapping (address => uint) balances; + mapping (address => mapping (address => uint)) allowed; + uint public totalSupply; +} + diff --git a/packages/contracts/contracts/tokens/EtherToken.sol b/packages/contracts/contracts/tokens/EtherToken.sol index 68148e095..2eae012fc 100644 --- a/packages/contracts/contracts/tokens/EtherToken.sol +++ b/packages/contracts/contracts/tokens/EtherToken.sol @@ -16,10 +16,10 @@ */ -pragma solidity 0.4.11; +pragma solidity ^0.4.11; import "./UnlimitedAllowanceToken.sol"; -import "./../base/SafeMath.sol"; +import "./../utils/SafeMath.sol"; contract EtherToken is UnlimitedAllowanceToken, SafeMath { @@ -54,3 +54,4 @@ contract EtherToken is UnlimitedAllowanceToken, SafeMath { require(msg.sender.send(amount)); } } + diff --git a/packages/contracts/contracts/tokens/EtherToken_v2.sol b/packages/contracts/contracts/tokens/EtherToken_v2.sol new file mode 100644 index 000000000..f172c8e35 --- /dev/null +++ b/packages/contracts/contracts/tokens/EtherToken_v2.sol @@ -0,0 +1,60 @@ +/* + + Copyright 2017 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.18; + +import "./UnlimitedAllowanceToken_v2.sol"; +import "./../utils/SafeMath_v2.sol"; + +contract EtherToken_v2 is UnlimitedAllowanceToken_v2, SafeMath_v2 { + + string constant public name = "Ether Token"; + string constant public symbol = "WETH"; + string constant public version = "2.0.0"; // version 1.0.0 deployed on mainnet at 0x2956356cd2a2bf3202f771f50d3d14a367b48070 + uint8 constant public decimals = 18; + + /// @dev Fallback to calling deposit when ether is sent directly to contract. + function() + public + payable + { + deposit(); + } + + /// @dev Buys tokens with Ether, exchanging them 1:1. + function deposit() + public + payable + { + balances[msg.sender] = safeAdd(balances[msg.sender], msg.value); + totalSupply = safeAdd(totalSupply, msg.value); + Transfer(address(0), msg.sender, msg.value); + } + + /// @dev Sells tokens in exchange for Ether, exchanging them 1:1. + /// @param _value Number of tokens to sell. + function withdraw(uint _value) + public + { + balances[msg.sender] = safeSub(balances[msg.sender], _value); + totalSupply = safeSub(totalSupply, _value); + require(msg.sender.send(_value)); + Transfer(msg.sender, address(0), _value); + } +} + diff --git a/packages/contracts/contracts/base/StandardToken.sol b/packages/contracts/contracts/tokens/StandardToken.sol index e0719d89a..9cd53d94a 100644 --- a/packages/contracts/contracts/base/StandardToken.sol +++ b/packages/contracts/contracts/tokens/StandardToken.sol @@ -1,4 +1,4 @@ -pragma solidity 0.4.11; +pragma solidity ^0.4.11; import "./Token.sol"; @@ -42,3 +42,4 @@ contract StandardToken is Token { mapping (address => mapping (address => uint)) allowed; uint public totalSupply; } + diff --git a/packages/contracts/contracts/base/Token.sol b/packages/contracts/contracts/tokens/Token.sol index c6a55c2c0..507de9b12 100644 --- a/packages/contracts/contracts/base/Token.sol +++ b/packages/contracts/contracts/tokens/Token.sol @@ -1,4 +1,4 @@ -pragma solidity 0.4.11; +pragma solidity ^0.4.11; contract Token { @@ -36,3 +36,4 @@ contract Token { event Transfer(address indexed _from, address indexed _to, uint _value); event Approval(address indexed _owner, address indexed _spender, uint _value); } + diff --git a/packages/contracts/contracts/tokens/Token_v2.sol b/packages/contracts/contracts/tokens/Token_v2.sol new file mode 100644 index 000000000..027f706f4 --- /dev/null +++ b/packages/contracts/contracts/tokens/Token_v2.sol @@ -0,0 +1,39 @@ +pragma solidity 0.4.18; + +contract Token_v2 { + + /// @return total amount of tokens + function totalSupply() public view returns (uint) {} + + /// @notice send `_value` token to `_to` from `msg.sender` + /// @param _to The address of the recipient + /// @param _value The amount of token to be transferred + /// @return Whether the transfer was successful or not + function transfer(address _to, uint _value) public returns (bool) {} + + /// @notice send `_value` token to `_to` from `_from` on the condition it is approved by `_from` + /// @param _from The address of the sender + /// @param _to The address of the recipient + /// @param _value The amount of token to be transferred + /// @return Whether the transfer was successful or not + function transferFrom(address _from, address _to, uint _value) public returns (bool) {} + + /// @notice `msg.sender` approves `_addr` to spend `_value` tokens + /// @param _spender The address of the account able to transfer the tokens + /// @param _value The amount of wei to be approved for transfer + /// @return Whether the approval was successful or not + function approve(address _spender, uint _value) public returns (bool) {} + + /// @param _owner The address from which the balance will be retrieved + /// @return The balance + function balanceOf(address _owner) public view returns (uint) {} + + /// @param _owner The address of the account owning tokens + /// @param _spender The address of the account able to transfer the tokens + /// @return Amount of remaining tokens allowed to spent + function allowance(address _owner, address _spender) public view returns (uint) {} + + event Transfer(address indexed _from, address indexed _to, uint _value); + event Approval(address indexed _owner, address indexed _spender, uint _value); +} + diff --git a/packages/contracts/contracts/tokens/UnlimitedAllowanceToken.sol b/packages/contracts/contracts/tokens/UnlimitedAllowanceToken.sol index 40e01b360..0994cfae4 100644 --- a/packages/contracts/contracts/tokens/UnlimitedAllowanceToken.sol +++ b/packages/contracts/contracts/tokens/UnlimitedAllowanceToken.sol @@ -16,9 +16,9 @@ */ -pragma solidity 0.4.11; +pragma solidity ^0.4.11; -import "./../base/StandardToken.sol"; +import "./StandardToken.sol"; contract UnlimitedAllowanceToken is StandardToken { @@ -50,3 +50,4 @@ contract UnlimitedAllowanceToken is StandardToken { } } } + diff --git a/packages/contracts/contracts/tokens/UnlimitedAllowanceToken_v2.sol b/packages/contracts/contracts/tokens/UnlimitedAllowanceToken_v2.sol new file mode 100644 index 000000000..b2caab8af --- /dev/null +++ b/packages/contracts/contracts/tokens/UnlimitedAllowanceToken_v2.sol @@ -0,0 +1,47 @@ +/* + + Copyright 2017 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.18; + +import "./ERC20Token.sol"; + +contract UnlimitedAllowanceToken_v2 is ERC20Token { + + uint constant MAX_UINT = 2**256 - 1; + + /// @dev ERC20 transferFrom, modified such that an allowance of MAX_UINT represents an unlimited allowance. See https://github.com/ethereum/EIPs/issues/717 + /// @param _from Address to transfer from. + /// @param _to Address to transfer to. + /// @param _value Amount to transfer. + /// @return Success of transfer. + function transferFrom(address _from, address _to, uint _value) + public + returns (bool) + { + uint allowance = allowed[_from][msg.sender]; + require(balances[_from] >= _value && allowance >= _value && balances[_to] + _value >= balances[_to]); + balances[_to] += _value; + balances[_from] -= _value; + if (allowance < MAX_UINT) { + allowed[_from][msg.sender] -= _value; + } + Transfer(_from, _to, _value); + return true; + } +} + diff --git a/packages/contracts/contracts/tokens/ZRXToken.sol b/packages/contracts/contracts/tokens/ZRXToken.sol index c8b9c08ab..af1dfac99 100644 --- a/packages/contracts/contracts/tokens/ZRXToken.sol +++ b/packages/contracts/contracts/tokens/ZRXToken.sol @@ -16,7 +16,7 @@ */ -pragma solidity 0.4.11; +pragma solidity ^0.4.11; import "./UnlimitedAllowanceToken.sol"; @@ -31,3 +31,4 @@ contract ZRXToken is UnlimitedAllowanceToken { balances[msg.sender] = totalSupply; } } + diff --git a/packages/contracts/contracts/base/Ownable.sol b/packages/contracts/contracts/utils/Ownable.sol index b7d6ac71c..77fdaf085 100644 --- a/packages/contracts/contracts/base/Ownable.sol +++ b/packages/contracts/contracts/utils/Ownable.sol @@ -1,4 +1,4 @@ -pragma solidity 0.4.11; +pragma solidity ^0.4.11; /* * Ownable @@ -25,3 +25,4 @@ contract Ownable { } } } + diff --git a/packages/contracts/contracts/utils/Ownable_v2.sol b/packages/contracts/contracts/utils/Ownable_v2.sol new file mode 100644 index 000000000..77e1fed08 --- /dev/null +++ b/packages/contracts/contracts/utils/Ownable_v2.sol @@ -0,0 +1,33 @@ +pragma solidity 0.4.18; + +/* + * Ownable + * + * Base contract with an owner. + * Provides onlyOwner modifier, which prevents function from running if it is called by anyone other than the owner. + */ + +contract Ownable_v2 { + address public owner; + + function Ownable_v2() + public + { + owner = msg.sender; + } + + modifier onlyOwner() { + require(msg.sender == owner); + _; + } + + function transferOwnership(address newOwner) + public + onlyOwner + { + if (newOwner != address(0)) { + owner = newOwner; + } + } +} + diff --git a/packages/contracts/contracts/utils/SafeMath.sol b/packages/contracts/contracts/utils/SafeMath.sol new file mode 100644 index 000000000..a7891a7af --- /dev/null +++ b/packages/contracts/contracts/utils/SafeMath.sol @@ -0,0 +1,74 @@ +pragma solidity ^0.4.11; + +contract SafeMath { + function safeMul(uint a, uint b) + internal + constant + returns (uint256) + { + uint c = a * b; + assert(a == 0 || c / a == b); + return c; + } + + function safeDiv(uint a, uint b) + internal + constant + returns (uint256) + { + uint c = a / b; + return c; + } + + function safeSub(uint a, uint b) + internal + constant + returns (uint256) + { + assert(b <= a); + return a - b; + } + + function safeAdd(uint a, uint b) + internal + constant + returns (uint256) + { + uint c = a + b; + assert(c >= a); + return c; + } + + function max64(uint64 a, uint64 b) + internal + constant + returns (uint64) + { + return a >= b ? a : b; + } + + function min64(uint64 a, uint64 b) + internal + constant + returns (uint64) + { + return a < b ? a : b; + } + + function max256(uint256 a, uint256 b) + internal + constant + returns (uint256) + { + return a >= b ? a : b; + } + + function min256(uint256 a, uint256 b) + internal + constant + returns (uint256) + { + return a < b ? a : b; + } +} + diff --git a/packages/contracts/contracts/utils/SafeMath_v2.sol b/packages/contracts/contracts/utils/SafeMath_v2.sol new file mode 100644 index 000000000..6eda03999 --- /dev/null +++ b/packages/contracts/contracts/utils/SafeMath_v2.sol @@ -0,0 +1,74 @@ +pragma solidity 0.4.18; + +contract SafeMath_v2 { + function safeMul(uint a, uint b) + internal + pure + returns (uint256) + { + uint c = a * b; + assert(a == 0 || c / a == b); + return c; + } + + function safeDiv(uint a, uint b) + internal + pure + returns (uint256) + { + uint c = a / b; + return c; + } + + function safeSub(uint a, uint b) + internal + pure + returns (uint256) + { + assert(b <= a); + return a - b; + } + + function safeAdd(uint a, uint b) + internal + pure + returns (uint256) + { + uint c = a + b; + assert(c >= a); + return c; + } + + function max64(uint64 a, uint64 b) + internal + pure + returns (uint256) + { + return a >= b ? a : b; + } + + function min64(uint64 a, uint64 b) + internal + pure + returns (uint256) + { + return a < b ? a : b; + } + + function max256(uint256 a, uint256 b) + internal + pure + returns (uint256) + { + return a >= b ? a : b; + } + + function min256(uint256 a, uint256 b) + internal + pure + returns (uint256) + { + return a < b ? a : b; + } +} + diff --git a/packages/contracts/deploy/test/util/constants.ts b/packages/contracts/deploy/test/util/constants.ts index a2de44b63..65525a1f7 100644 --- a/packages/contracts/deploy/test/util/constants.ts +++ b/packages/contracts/deploy/test/util/constants.ts @@ -5,7 +5,7 @@ export const constants = { jsonrpcPort: 8545, optimizerEnabled: 0, gasPrice: new BigNumber(20000000000), - timeoutMs: 12000, + timeoutMs: 20000, zrxTokenAddress: '0xe41d2489571d322189246dafa5ebde1f4699f498', tokenTransferProxyAddress: '0x8da0d80f5007ef1e431dd2127178d224e32c2ef4', }; diff --git a/packages/contracts/migrations/2_deploy_independent_contracts.ts b/packages/contracts/migrations/2_deploy_independent_contracts.ts index 878860eb6..db9fc370d 100644 --- a/packages/contracts/migrations/2_deploy_independent_contracts.ts +++ b/packages/contracts/migrations/2_deploy_independent_contracts.ts @@ -4,6 +4,7 @@ const { MultiSigWalletWithTimeLock, TokenTransferProxy, EtherToken, + EtherTokenV2, TokenRegistry, } = new Artifacts(artifacts); @@ -28,11 +29,13 @@ module.exports = (deployer: any, network: string, accounts: string[]) => { deployer.deploy(MultiSigWalletWithTimeLock, config.owners, config.confirmationsRequired, config.secondsRequired) .then(() => { - return deployer.deploy(TokenTransferProxy); + return deployer.deploy(TokenTransferProxy); }).then(() => { - return deployer.deploy(TokenRegistry); + return deployer.deploy(TokenRegistry); }).then(() => { - return deployer.deploy(EtherToken); + return deployer.deploy(EtherToken); + }).then(() => { + return deployer.deploy(EtherTokenV2); }); } else { deployer.deploy([ diff --git a/packages/contracts/package.json b/packages/contracts/package.json index d2f30933a..f4d0b5865 100644 --- a/packages/contracts/package.json +++ b/packages/contracts/package.json @@ -15,6 +15,7 @@ "migrate:truffle": "npm run build; truffle migrate", "migrate": "npm run build; node lib/deploy/cli.js migrate", "lint": "tslint --project . 'migrations/**/*.ts' 'test/**/*.ts' 'util/**/*.ts' 'deploy/**/*.ts'", + "test:circleci": "yarn test; yarn test:deployer", "test:deployer": "npm run build; mocha lib/deploy/test/*_test.js" }, "repository": { @@ -31,7 +32,6 @@ "@0xproject/tslint-config": "^0.2.1", "@0xproject/types": "^0.1.0", "@types/bluebird": "^3.5.3", - "@types/isomorphic-fetch": "^0.0.34", "@types/lodash": "^4.14.86", "@types/node": "^8.0.53", "@types/request-promise-native": "^1.0.2", @@ -45,7 +45,7 @@ "dirty-chai": "^2.0.1", "mocha": "^4.0.1", "solc": "^0.4.18", - "truffle": "3.4.3", + "truffle": "^4.0.1", "tslint": "5.8.0", "types-bn": "^0.0.1", "types-ethereumjs-util": "0xProject/types-ethereumjs-util", @@ -54,7 +54,7 @@ "yargs": "^10.0.3" }, "dependencies": { - "0x.js": "^0.22.6", + "0x.js": "^0.27.1", "@0xproject/json-schemas": "^0.6.10", "@0xproject/utils": "^0.1.0", "@0xproject/web3-wrapper": "^0.1.0", diff --git a/packages/contracts/test/ts/ether_token.ts b/packages/contracts/test/ts/ether_token.ts index dbb4d2ee6..2f9df59a4 100644 --- a/packages/contracts/test/ts/ether_token.ts +++ b/packages/contracts/test/ts/ether_token.ts @@ -5,6 +5,7 @@ import * as chai from 'chai'; import Web3 = require('web3'); import {Artifacts} from '../../util/artifacts'; +import {constants} from '../../util/constants'; import {chaiSetup} from './utils/chai_setup'; @@ -22,11 +23,13 @@ contract('EtherToken', (accounts: string[]) => { const gasPrice = ZeroEx.toBaseUnitAmount(new BigNumber(20), 9); let zeroEx: ZeroEx; let etherTokenAddress: string; + before(async () => { etherTokenAddress = EtherToken.address; zeroEx = new ZeroEx(web3.currentProvider, { - gasPrice, - etherTokenContractAddress: etherTokenAddress, + gasPrice, + etherTokenContractAddress: etherTokenAddress, + networkId: constants.TESTRPC_NETWORK_ID, }); }); @@ -78,7 +81,9 @@ contract('EtherToken', (accounts: string[]) => { const initEthBalance = await getEthBalanceAsync(account); const ethTokensToWithdraw = initEthTokenBalance; expect(ethTokensToWithdraw).to.not.be.bignumber.equal(0); - const txHash = await zeroEx.etherToken.withdrawAsync(ethTokensToWithdraw, account); + const txHash = await zeroEx.etherToken.withdrawAsync(ethTokensToWithdraw, account, { + gasLimit: constants.MAX_ETHERTOKEN_WITHDRAW_GAS, + }); const receipt = await zeroEx.awaitTransactionMinedAsync(txHash); const ethSpentOnGas = gasPrice.times(receipt.gasUsed); diff --git a/packages/contracts/test/ts/ether_token_v2.ts b/packages/contracts/test/ts/ether_token_v2.ts new file mode 100644 index 000000000..b88fef579 --- /dev/null +++ b/packages/contracts/test/ts/ether_token_v2.ts @@ -0,0 +1,168 @@ +import {ZeroEx, ZeroExError} from '0x.js'; +import {promisify} from '@0xproject/utils'; +import {BigNumber} from 'bignumber.js'; +import * as chai from 'chai'; +import Web3 = require('web3'); + +import {Artifacts} from '../../util/artifacts'; +import {constants} from '../../util/constants'; + +import {chaiSetup} from './utils/chai_setup'; + +const {EtherTokenV2} = new Artifacts(artifacts); + +chaiSetup.configure(); +const expect = chai.expect; + +// In order to benefit from type-safety, we re-assign the global web3 instance injected by Truffle +// with type `any` to a variable of type `Web3`. +const web3: Web3 = (global as any).web3; + +contract('EtherTokenV2', (accounts: string[]) => { + const account = accounts[0]; + const gasPrice = ZeroEx.toBaseUnitAmount(new BigNumber(20), 9); + let zeroEx: ZeroEx; + let etherTokenAddress: string; + beforeEach(async () => { + const etherToken = await EtherTokenV2.new(); + etherTokenAddress = etherToken.address; + zeroEx = new ZeroEx(web3.currentProvider, { + gasPrice, + etherTokenContractAddress: etherTokenAddress, + networkId: constants.TESTRPC_NETWORK_ID, + }); + }); + + const sendTransactionAsync = promisify<string>(web3.eth.sendTransaction); + const getEthBalanceAsync = async (owner: string) => { + const balanceStr = await promisify<string>(web3.eth.getBalance)(owner); + const balance = new BigNumber(balanceStr); + return balance; + }; + + describe('deposit', () => { + it('should throw if caller attempts to deposit more Ether than caller balance', async () => { + const initEthBalance = await getEthBalanceAsync(account); + const ethToDeposit = initEthBalance.plus(1); + + return expect(zeroEx.etherToken.depositAsync(ethToDeposit, account)) + .to.be.rejectedWith(ZeroExError.InsufficientEthBalanceForDeposit); + }); + + it('should convert deposited Ether to wrapped Ether tokens', async () => { + const initEthBalance = await getEthBalanceAsync(account); + const initEthTokenBalance = await zeroEx.token.getBalanceAsync(etherTokenAddress, account); + + const ethToDeposit = new BigNumber(web3.toWei(1, 'ether')); + + const txHash = await zeroEx.etherToken.depositAsync(ethToDeposit, account); + const receipt = await zeroEx.awaitTransactionMinedAsync(txHash); + + const ethSpentOnGas = gasPrice.times(receipt.gasUsed); + const finalEthBalance = await getEthBalanceAsync(account); + const finalEthTokenBalance = await zeroEx.token.getBalanceAsync(etherTokenAddress, account); + + expect(finalEthBalance).to.be.bignumber.equal(initEthBalance.minus(ethToDeposit.plus(ethSpentOnGas))); + expect(finalEthTokenBalance).to.be.bignumber.equal(initEthTokenBalance.plus(ethToDeposit)); + }); + + it('should log 1 event with correct arguments', async () => { + const ethToDeposit = new BigNumber(web3.toWei(1, 'ether')); + + const txHash = await zeroEx.etherToken.depositAsync(ethToDeposit, account); + const receipt = await zeroEx.awaitTransactionMinedAsync(txHash); + + const logs = receipt.logs; + expect(logs.length).to.equal(1); + + const expectedFrom = ZeroEx.NULL_ADDRESS; + const expectedTo = account; + const expectedValue = ethToDeposit; + const logArgs = (logs[0] as any).args; + expect(logArgs._from).to.equal(expectedFrom); + expect(logArgs._to).to.equal(expectedTo); + expect(logArgs._value).to.be.bignumber.equal(ethToDeposit); + }); + }); + + describe('withdraw', () => { + beforeEach(async () => { + const ethToDeposit = new BigNumber(web3.toWei(1, 'ether')); + await zeroEx.etherToken.depositAsync(ethToDeposit, account); + }); + + it('should throw if caller attempts to withdraw greater than caller balance', async () => { + const initEthTokenBalance = await zeroEx.token.getBalanceAsync(etherTokenAddress, account); + const ethTokensToWithdraw = initEthTokenBalance.plus(1); + + return expect(zeroEx.etherToken.withdrawAsync(ethTokensToWithdraw, account)) + .to.be.rejectedWith(ZeroExError.InsufficientWEthBalanceForWithdrawal); + }); + + it('should convert ether tokens to ether with sufficient balance', async () => { + const initEthTokenBalance = await zeroEx.token.getBalanceAsync(etherTokenAddress, account); + const initEthBalance = await getEthBalanceAsync(account); + const ethTokensToWithdraw = initEthTokenBalance; + expect(ethTokensToWithdraw).to.not.be.bignumber.equal(0); + const txHash = await zeroEx.etherToken.withdrawAsync(ethTokensToWithdraw, account, { + gasLimit: constants.MAX_ETHERTOKEN_WITHDRAW_GAS, + }); + const receipt = await zeroEx.awaitTransactionMinedAsync(txHash); + + const ethSpentOnGas = gasPrice.times(receipt.gasUsed); + const finalEthBalance = await getEthBalanceAsync(account); + const finalEthTokenBalance = await zeroEx.token.getBalanceAsync(etherTokenAddress, account); + + expect(finalEthBalance).to.be.bignumber + .equal(initEthBalance.plus(ethTokensToWithdraw.minus(ethSpentOnGas))); + expect(finalEthTokenBalance).to.be.bignumber.equal(initEthTokenBalance.minus(ethTokensToWithdraw)); + }); + + it('should log 1 event with correct arguments', async () => { + const initEthTokenBalance = await zeroEx.token.getBalanceAsync(etherTokenAddress, account); + const initEthBalance = await getEthBalanceAsync(account); + const ethTokensToWithdraw = initEthTokenBalance; + expect(ethTokensToWithdraw).to.not.be.bignumber.equal(0); + const txHash = await zeroEx.etherToken.withdrawAsync(ethTokensToWithdraw, account, { + gasLimit: constants.MAX_ETHERTOKEN_WITHDRAW_GAS, + }); + const receipt = await zeroEx.awaitTransactionMinedAsync(txHash); + + const logs = receipt.logs; + expect(logs.length).to.equal(1); + + const expectedFrom = account; + const expectedTo = ZeroEx.NULL_ADDRESS; + const expectedValue = ethTokensToWithdraw; + const logArgs = (logs[0] as any).args; + expect(logArgs._from).to.equal(expectedFrom); + expect(logArgs._to).to.equal(expectedTo); + expect(logArgs._value).to.be.bignumber.equal(ethTokensToWithdraw); + }); + }); + + describe('fallback', () => { + it('should convert sent ether to ether tokens', async () => { + const initEthBalance = await getEthBalanceAsync(account); + const initEthTokenBalance = await zeroEx.token.getBalanceAsync(etherTokenAddress, account); + + const ethToDeposit = ZeroEx.toBaseUnitAmount(new BigNumber(1), 18); + + const txHash = await sendTransactionAsync({ + from: account, + to: etherTokenAddress, + value: ethToDeposit, + gasPrice, + }); + + const receipt = await zeroEx.awaitTransactionMinedAsync(txHash); + + const ethSpentOnGas = gasPrice.times(receipt.gasUsed); + const finalEthBalance = await getEthBalanceAsync(account); + const finalEthTokenBalance = await zeroEx.token.getBalanceAsync(etherTokenAddress, account); + + expect(finalEthBalance).to.be.bignumber.equal(initEthBalance.minus(ethToDeposit.plus(ethSpentOnGas))); + expect(finalEthTokenBalance).to.be.bignumber.equal(initEthTokenBalance.plus(ethToDeposit)); + }); + }); +}); diff --git a/packages/contracts/test/ts/exchange/core.ts b/packages/contracts/test/ts/exchange/core.ts index daf46ca37..641084937 100644 --- a/packages/contracts/test/ts/exchange/core.ts +++ b/packages/contracts/test/ts/exchange/core.ts @@ -59,6 +59,7 @@ contract('Exchange', (accounts: string[]) => { exWrapper = new ExchangeWrapper(exchange); zeroEx = new ZeroEx(web3.currentProvider, { exchangeContractAddress: exchange.address, + networkId: constants.TESTRPC_NETWORK_ID, }); const [repAddress, dgdAddress, zrxAddress] = await Promise.all([ @@ -422,7 +423,7 @@ contract('Exchange', (accounts: string[]) => { takerTokenAmount: ZeroEx.toBaseUnitAmount(new BigNumber(200), 18), }); - return expect(exWrapper.fillOrderAsync(order, taker)).to.be.rejectedWith(constants.INVALID_OPCODE); + return expect(exWrapper.fillOrderAsync(order, taker)).to.be.rejectedWith(constants.REVERT); }); it('should throw if signature is invalid', async () => { @@ -432,7 +433,7 @@ contract('Exchange', (accounts: string[]) => { order.params.r = ethUtil.bufferToHex(ethUtil.sha3('invalidR')); order.params.s = ethUtil.bufferToHex(ethUtil.sha3('invalidS')); - return expect(exWrapper.fillOrderAsync(order, taker)).to.be.rejectedWith(constants.INVALID_OPCODE); + return expect(exWrapper.fillOrderAsync(order, taker)).to.be.rejectedWith(constants.REVERT); }); it('should throw if makerTokenAmount is 0', async () => { @@ -440,7 +441,7 @@ contract('Exchange', (accounts: string[]) => { makerTokenAmount: new BigNumber(0), }); - return expect(exWrapper.fillOrderAsync(order, taker)).to.be.rejectedWith(constants.INVALID_OPCODE); + return expect(exWrapper.fillOrderAsync(order, taker)).to.be.rejectedWith(constants.REVERT); }); it('should throw if takerTokenAmount is 0', async () => { @@ -448,14 +449,14 @@ contract('Exchange', (accounts: string[]) => { takerTokenAmount: new BigNumber(0), }); - return expect(exWrapper.fillOrderAsync(order, taker)).to.be.rejectedWith(constants.INVALID_OPCODE); + return expect(exWrapper.fillOrderAsync(order, taker)).to.be.rejectedWith(constants.REVERT); }); it('should throw if fillTakerTokenAmount is 0', async () => { order = await orderFactory.newSignedOrderAsync(); return expect(exWrapper.fillOrderAsync(order, taker, {fillTakerTokenAmount: new BigNumber(0)})) - .to.be.rejectedWith(constants.INVALID_OPCODE); + .to.be.rejectedWith(constants.REVERT); }); it('should not change balances if maker balances are too low to fill order and \ @@ -478,7 +479,7 @@ contract('Exchange', (accounts: string[]) => { }); return expect(exWrapper.fillOrderAsync(order, taker, {shouldThrowOnInsufficientBalanceOrAllowance: true})) - .to.be.rejectedWith(constants.INVALID_OPCODE); + .to.be.rejectedWith(constants.REVERT); }); it('should not change balances if taker balances are too low to fill order and \ @@ -501,7 +502,7 @@ contract('Exchange', (accounts: string[]) => { }); return expect(exWrapper.fillOrderAsync(order, taker, {shouldThrowOnInsufficientBalanceOrAllowance: true})) - .to.be.rejectedWith(constants.INVALID_OPCODE); + .to.be.rejectedWith(constants.REVERT); }); it('should not change balances if maker allowances are too low to fill order and \ @@ -520,7 +521,7 @@ contract('Exchange', (accounts: string[]) => { async () => { await rep.approve(TokenTransferProxy.address, 0, {from: maker}); expect(exWrapper.fillOrderAsync(order, taker, {shouldThrowOnInsufficientBalanceOrAllowance: true})) - .to.be.rejectedWith(constants.INVALID_OPCODE); + .to.be.rejectedWith(constants.REVERT); await rep.approve(TokenTransferProxy.address, INITIAL_ALLOWANCE, {from: maker}); }); @@ -540,7 +541,7 @@ contract('Exchange', (accounts: string[]) => { async () => { await dgd.approve(TokenTransferProxy.address, 0, {from: taker}); expect(exWrapper.fillOrderAsync(order, taker, {shouldThrowOnInsufficientBalanceOrAllowance: true})) - .to.be.rejectedWith(constants.INVALID_OPCODE); + .to.be.rejectedWith(constants.REVERT); await dgd.approve(TokenTransferProxy.address, INITIAL_ALLOWANCE, {from: taker}); }); @@ -610,7 +611,7 @@ contract('Exchange', (accounts: string[]) => { }); return expect(exWrapper.fillOrderAsync(order, taker, {shouldThrowOnInsufficientBalanceOrAllowance: false})) - .to.be.rejectedWith(constants.INVALID_OPCODE); + .to.be.rejectedWith(constants.REVERT); }); it('should not change balances if an order is expired', async () => { @@ -651,7 +652,7 @@ contract('Exchange', (accounts: string[]) => { }); it('should throw if not sent by maker', async () => { - return expect(exWrapper.cancelOrderAsync(order, taker)).to.be.rejectedWith(constants.INVALID_OPCODE); + return expect(exWrapper.cancelOrderAsync(order, taker)).to.be.rejectedWith(constants.REVERT); }); it('should throw if makerTokenAmount is 0', async () => { @@ -659,7 +660,7 @@ contract('Exchange', (accounts: string[]) => { makerTokenAmount: new BigNumber(0), }); - return expect(exWrapper.cancelOrderAsync(order, maker)).to.be.rejectedWith(constants.INVALID_OPCODE); + return expect(exWrapper.cancelOrderAsync(order, maker)).to.be.rejectedWith(constants.REVERT); }); it('should throw if takerTokenAmount is 0', async () => { @@ -667,14 +668,14 @@ contract('Exchange', (accounts: string[]) => { takerTokenAmount: new BigNumber(0), }); - return expect(exWrapper.cancelOrderAsync(order, maker)).to.be.rejectedWith(constants.INVALID_OPCODE); + return expect(exWrapper.cancelOrderAsync(order, maker)).to.be.rejectedWith(constants.REVERT); }); it('should throw if cancelTakerTokenAmount is 0', async () => { order = await orderFactory.newSignedOrderAsync(); return expect(exWrapper.cancelOrderAsync(order, maker, {cancelTakerTokenAmount: new BigNumber(0)})) - .to.be.rejectedWith(constants.INVALID_OPCODE); + .to.be.rejectedWith(constants.REVERT); }); it('should be able to cancel a full order', async () => { diff --git a/packages/contracts/test/ts/exchange/wrapper.ts b/packages/contracts/test/ts/exchange/wrapper.ts index c40d60104..3097f6887 100644 --- a/packages/contracts/test/ts/exchange/wrapper.ts +++ b/packages/contracts/test/ts/exchange/wrapper.ts @@ -133,7 +133,7 @@ contract('Exchange', (accounts: string[]) => { }); return expect(exWrapper.fillOrKillOrderAsync(order, taker)) - .to.be.rejectedWith(constants.INVALID_OPCODE); + .to.be.rejectedWith(constants.REVERT); }); it('should throw if entire fillTakerTokenAmount not filled', async () => { @@ -143,7 +143,7 @@ contract('Exchange', (accounts: string[]) => { await exWrapper.fillOrderAsync(order, from, {fillTakerTokenAmount: order.params.takerTokenAmount.div(2)}); return expect(exWrapper.fillOrKillOrderAsync(order, taker)) - .to.be.rejectedWith(constants.INVALID_OPCODE); + .to.be.rejectedWith(constants.REVERT); }); }); @@ -237,7 +237,7 @@ contract('Exchange', (accounts: string[]) => { await exWrapper.fillOrKillOrderAsync(orders[0], taker); return expect(exWrapper.batchFillOrKillOrdersAsync(orders, taker, {fillTakerTokenAmounts})) - .to.be.rejectedWith(constants.INVALID_OPCODE); + .to.be.rejectedWith(constants.REVERT); }); }); @@ -302,7 +302,7 @@ contract('Exchange', (accounts: string[]) => { return expect( exWrapper.fillOrdersUpToAsync( orders, taker, {fillTakerTokenAmount: ZeroEx.toBaseUnitAmount(new BigNumber(1000), 18)}), - ).to.be.rejectedWith(constants.INVALID_OPCODE); + ).to.be.rejectedWith(constants.REVERT); }); }); diff --git a/packages/contracts/test/ts/multi_sig_with_time_lock.ts b/packages/contracts/test/ts/multi_sig_with_time_lock.ts index 6dd4dc3b2..84eb21b4a 100644 --- a/packages/contracts/test/ts/multi_sig_with_time_lock.ts +++ b/packages/contracts/test/ts/multi_sig_with_time_lock.ts @@ -44,7 +44,7 @@ contract('MultiSigWalletWithTimeLock', (accounts: string[]) => { describe('changeTimeLock', () => { it('should throw when not called by wallet', async () => { return expect(multiSig.changeTimeLock(SECONDS_TIME_LOCKED, {from: owners[0]})) - .to.be.rejectedWith(constants.INVALID_OPCODE); + .to.be.rejectedWith(constants.REVERT); }); it('should throw without enough confirmations', async () => { @@ -58,7 +58,7 @@ contract('MultiSigWalletWithTimeLock', (accounts: string[]) => { const subRes = await multiSigWrapper.submitTransactionAsync(destination, from, dataParams); txId = subRes.logs[0].args.transactionId.toNumber(); - return expect(multiSig.executeTransaction(txId)).to.be.rejectedWith(constants.INVALID_OPCODE); + return expect(multiSig.executeTransaction(txId)).to.be.rejectedWith(constants.REVERT); }); it('should set confirmation time with enough confirmations', async () => { @@ -97,7 +97,7 @@ contract('MultiSigWalletWithTimeLock', (accounts: string[]) => { const confRes = await multiSig.confirmTransaction(txId, {from: owners[1]}); expect(confRes.logs).to.have.length(2); - return expect(multiSig.executeTransaction(txId)).to.be.rejectedWith(constants.INVALID_OPCODE); + return expect(multiSig.executeTransaction(txId)).to.be.rejectedWith(constants.REVERT); }); it('should execute if it has enough confirmations and is past the time lock', async () => { diff --git a/packages/contracts/test/ts/multi_sig_with_time_lock_except_remove_auth_addr.ts b/packages/contracts/test/ts/multi_sig_with_time_lock_except_remove_auth_addr.ts index 97ccac2bd..6f7aaa6cd 100644 --- a/packages/contracts/test/ts/multi_sig_with_time_lock_except_remove_auth_addr.ts +++ b/packages/contracts/test/ts/multi_sig_with_time_lock_except_remove_auth_addr.ts @@ -44,7 +44,7 @@ contract('MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress', (accounts: s it('should throw if data is not for removeAuthorizedAddress', async () => { const data = MultiSigWrapper.encodeFnArgs('addAuthorizedAddress', PROXY_ABI, [owners[0]]); return expect(multiSig.isFunctionRemoveAuthorizedAddress.call(data)) - .to.be.rejectedWith(constants.INVALID_OPCODE); + .to.be.rejectedWith(constants.REVERT); }); it('should return true if data is for removeAuthorizedAddress', async () => { @@ -64,7 +64,7 @@ contract('MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress', (accounts: s const res = await multiSigWrapper.submitTransactionAsync(validDestination, owners[0], dataParams); const txId = res.logs[0].args.transactionId.toString(); - return expect(multiSig.executeRemoveAuthorizedAddress(txId)).to.be.rejectedWith(constants.INVALID_OPCODE); + return expect(multiSig.executeRemoveAuthorizedAddress(txId)).to.be.rejectedWith(constants.REVERT); }); it('should throw if tx destination is not the tokenTransferProxy', async () => { @@ -81,7 +81,7 @@ contract('MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress', (accounts: s const isConfirmed = await multiSig.isConfirmed.call(txId); expect(isConfirmed).to.be.true(); - return expect(multiSig.executeRemoveAuthorizedAddress(txId)).to.be.rejectedWith(constants.INVALID_OPCODE); + return expect(multiSig.executeRemoveAuthorizedAddress(txId)).to.be.rejectedWith(constants.REVERT); }); it('should throw if tx data is not for removeAuthorizedAddress', async () => { @@ -96,7 +96,7 @@ contract('MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress', (accounts: s const isConfirmed = await multiSig.isConfirmed.call(txId); expect(isConfirmed).to.be.true(); - return expect(multiSig.executeRemoveAuthorizedAddress(txId)).to.be.rejectedWith(constants.INVALID_OPCODE); + return expect(multiSig.executeRemoveAuthorizedAddress(txId)).to.be.rejectedWith(constants.REVERT); }); it('should execute removeAuthorizedAddress for valid tokenTransferProxy if fully confirmed', async () => { @@ -131,7 +131,7 @@ contract('MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress', (accounts: s const tx = await multiSig.transactions.call(txId); const isExecuted = tx[3]; expect(isExecuted).to.be.true(); - return expect(multiSig.executeRemoveAuthorizedAddress(txId)).to.be.rejectedWith(constants.INVALID_OPCODE); + return expect(multiSig.executeRemoveAuthorizedAddress(txId)).to.be.rejectedWith(constants.REVERT); }); }); }); diff --git a/packages/contracts/test/ts/token_registry.ts b/packages/contracts/test/ts/token_registry.ts index ed0bbf55b..36f3edcfc 100644 --- a/packages/contracts/test/ts/token_registry.ts +++ b/packages/contracts/test/ts/token_registry.ts @@ -58,7 +58,7 @@ contract('TokenRegistry', (accounts: string[]) => { describe('addToken', () => { it('should throw when not called by owner', async () => { - return expect(tokenRegWrapper.addTokenAsync(token1, notOwner)).to.be.rejectedWith(constants.INVALID_OPCODE); + return expect(tokenRegWrapper.addTokenAsync(token1, notOwner)).to.be.rejectedWith(constants.REVERT); }); it('should add token metadata when called by owner', async () => { @@ -70,11 +70,11 @@ contract('TokenRegistry', (accounts: string[]) => { it('should throw if token already exists', async () => { await tokenRegWrapper.addTokenAsync(token1, owner); - return expect(tokenRegWrapper.addTokenAsync(token1, owner)).to.be.rejectedWith(constants.INVALID_OPCODE); + return expect(tokenRegWrapper.addTokenAsync(token1, owner)).to.be.rejectedWith(constants.REVERT); }); it('should throw if token address is null', async () => { - return expect(tokenRegWrapper.addTokenAsync(nullToken, owner)).to.be.rejectedWith(constants.INVALID_OPCODE); + return expect(tokenRegWrapper.addTokenAsync(nullToken, owner)).to.be.rejectedWith(constants.REVERT); }); it('should throw if name already exists', async () => { @@ -82,7 +82,7 @@ contract('TokenRegistry', (accounts: string[]) => { const duplicateNameToken = _.assign({}, token2, {name: token1.name}); return expect(tokenRegWrapper.addTokenAsync(duplicateNameToken, owner)) - .to.be.rejectedWith(constants.INVALID_OPCODE); + .to.be.rejectedWith(constants.REVERT); }); it('should throw if symbol already exists', async () => { @@ -90,7 +90,7 @@ contract('TokenRegistry', (accounts: string[]) => { const duplicateSymbolToken = _.assign({}, token2, {symbol: token1.symbol}); return expect(tokenRegWrapper.addTokenAsync(duplicateSymbolToken, owner)) - .to.be.rejectedWith(constants.INVALID_OPCODE); + .to.be.rejectedWith(constants.REVERT); }); }); @@ -116,7 +116,7 @@ contract('TokenRegistry', (accounts: string[]) => { describe('setTokenName', () => { it('should throw when not called by owner', async () => { return expect(tokenReg.setTokenName(token1.address, token2.name, {from: notOwner})) - .to.be.rejectedWith(constants.INVALID_OPCODE); + .to.be.rejectedWith(constants.REVERT); }); it('should change the token name when called by owner', async () => { @@ -137,19 +137,19 @@ contract('TokenRegistry', (accounts: string[]) => { await tokenRegWrapper.addTokenAsync(token2, owner); return expect(tokenReg.setTokenName(token1.address, token2.name, {from: owner})) - .to.be.rejectedWith(constants.INVALID_OPCODE); + .to.be.rejectedWith(constants.REVERT); }); it('should throw if token does not exist', async () => { return expect(tokenReg.setTokenName(nullToken.address, token2.name, {from: owner})) - .to.be.rejectedWith(constants.INVALID_OPCODE); + .to.be.rejectedWith(constants.REVERT); }); }); describe('setTokenSymbol', () => { it('should throw when not called by owner', async () => { return expect(tokenReg.setTokenSymbol(token1.address, token2.symbol, {from: notOwner})) - .to.be.rejectedWith(constants.INVALID_OPCODE); + .to.be.rejectedWith(constants.REVERT); }); it('should change the token symbol when called by owner', async () => { @@ -170,12 +170,12 @@ contract('TokenRegistry', (accounts: string[]) => { await tokenRegWrapper.addTokenAsync(token2, owner); return expect(tokenReg.setTokenSymbol(token1.address, token2.symbol, {from: owner})) - .to.be.rejectedWith(constants.INVALID_OPCODE); + .to.be.rejectedWith(constants.REVERT); }); it('should throw if token does not exist', async () => { return expect(tokenReg.setTokenSymbol(nullToken.address, token2.symbol, {from: owner})) - .to.be.rejectedWith(constants.INVALID_OPCODE); + .to.be.rejectedWith(constants.REVERT); }); }); @@ -183,7 +183,7 @@ contract('TokenRegistry', (accounts: string[]) => { it('should throw if not called by owner', async () => { const index = 0; return expect(tokenReg.removeToken(token1.address, index, {from: notOwner})) - .to.be.rejectedWith(constants.INVALID_OPCODE); + .to.be.rejectedWith(constants.REVERT); }); it('should remove token metadata when called by owner', async () => { @@ -197,14 +197,14 @@ contract('TokenRegistry', (accounts: string[]) => { it('should throw if token does not exist', async () => { const index = 0; return expect(tokenReg.removeToken(nullToken.address, index, {from: owner})) - .to.be.rejectedWith(constants.INVALID_OPCODE); + .to.be.rejectedWith(constants.REVERT); }); it('should throw if token at given index does not match address', async () => { await tokenRegWrapper.addTokenAsync(token2, owner); const incorrectIndex = 0; return expect(tokenReg.removeToken(token2.address, incorrectIndex, {from: owner})) - .to.be.rejectedWith(constants.INVALID_OPCODE); + .to.be.rejectedWith(constants.REVERT); }); }); diff --git a/packages/contracts/test/ts/token_transfer_proxy/auth.ts b/packages/contracts/test/ts/token_transfer_proxy/auth.ts index 785fbc016..7c0a3d231 100644 --- a/packages/contracts/test/ts/token_transfer_proxy/auth.ts +++ b/packages/contracts/test/ts/token_transfer_proxy/auth.ts @@ -23,7 +23,7 @@ contract('TokenTransferProxy', (accounts: string[]) => { describe('addAuthorizedAddress', () => { it('should throw if not called by owner', async () => { return expect(tokenTransferProxy.addAuthorizedAddress(notOwner, {from: notOwner})) - .to.be.rejectedWith(constants.INVALID_OPCODE); + .to.be.rejectedWith(constants.REVERT); }); it('should allow owner to add an authorized address', async () => { @@ -36,14 +36,14 @@ contract('TokenTransferProxy', (accounts: string[]) => { it('should throw if owner attempts to authorize a duplicate address', async () => { return expect(tokenTransferProxy.addAuthorizedAddress(authorized, {from: owner})) - .to.be.rejectedWith(constants.INVALID_OPCODE); + .to.be.rejectedWith(constants.REVERT); }); }); describe('removeAuthorizedAddress', () => { it('should throw if not called by owner', async () => { return expect(tokenTransferProxy.removeAuthorizedAddress(authorized, {from: notOwner})) - .to.be.rejectedWith(constants.INVALID_OPCODE); + .to.be.rejectedWith(constants.REVERT); }); it('should allow owner to remove an authorized address', async () => { @@ -57,7 +57,7 @@ contract('TokenTransferProxy', (accounts: string[]) => { it('should throw if owner attempts to remove an address that is not authorized', async () => { return expect(tokenTransferProxy.removeAuthorizedAddress(notAuthorized, {from: owner})) - .to.be.rejectedWith(constants.INVALID_OPCODE); + .to.be.rejectedWith(constants.REVERT); }); }); diff --git a/packages/contracts/test/ts/token_transfer_proxy/transfer_from.ts b/packages/contracts/test/ts/token_transfer_proxy/transfer_from.ts index 6e0bfdc1a..8b40bfb1e 100644 --- a/packages/contracts/test/ts/token_transfer_proxy/transfer_from.ts +++ b/packages/contracts/test/ts/token_transfer_proxy/transfer_from.ts @@ -46,7 +46,7 @@ contract('TokenTransferProxy', (accounts: string[]) => { describe('transferFrom', () => { it('should throw when called by an unauthorized address', async () => { expect(tokenTransferProxy.transferFrom(rep.address, accounts[0], accounts[1], 1000, {from: notAuthorized})) - .to.be.rejectedWith(constants.INVALID_OPCODE); + .to.be.rejectedWith(constants.REVERT); }); it('should allow an authorized address to transfer', async () => { diff --git a/packages/contracts/test/ts/unlimitedAllowanceToken.ts b/packages/contracts/test/ts/unlimited_allowance_token.ts index ca3fcd7d2..33b2a5721 100644 --- a/packages/contracts/test/ts/unlimitedAllowanceToken.ts +++ b/packages/contracts/test/ts/unlimited_allowance_token.ts @@ -4,6 +4,7 @@ import * as chai from 'chai'; import * as Web3 from 'web3'; import {Artifacts} from '../../util/artifacts'; +import {constants} from '../../util/constants'; import {ContractInstance} from '../../util/types'; import {chaiSetup} from './utils/chai_setup'; @@ -14,7 +15,10 @@ chaiSetup.configure(); const expect = chai.expect; contract('UnlimitedAllowanceToken', (accounts: string[]) => { - const zeroEx = new ZeroEx(web3.currentProvider); + const config = { + networkId: constants.TESTRPC_NETWORK_ID, + }; + const zeroEx = new ZeroEx(web3.currentProvider, config); const owner = accounts[0]; const spender = accounts[1]; @@ -81,7 +85,9 @@ contract('UnlimitedAllowanceToken', (accounts: string[]) => { const amountToTransfer = initOwnerBalance; const initSpenderAllowance = zeroEx.token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS; await zeroEx.token.setAllowanceAsync(tokenAddress, owner, spender, initSpenderAllowance); - await zeroEx.token.transferFromAsync(tokenAddress, owner, spender, spender, amountToTransfer); + await zeroEx.token.transferFromAsync(tokenAddress, owner, spender, spender, amountToTransfer, { + gasLimit: constants.MAX_TOKEN_TRANSFERFROM_GAS, + }); const newSpenderAllowance = await zeroEx.token.getAllowanceAsync(tokenAddress, owner, spender); expect(initSpenderAllowance).to.be.bignumber.equal(newSpenderAllowance); @@ -92,7 +98,9 @@ contract('UnlimitedAllowanceToken', (accounts: string[]) => { const amountToTransfer = initOwnerBalance; const initSpenderAllowance = initOwnerBalance; await zeroEx.token.setAllowanceAsync(tokenAddress, owner, spender, initSpenderAllowance); - await zeroEx.token.transferFromAsync(tokenAddress, owner, spender, spender, amountToTransfer); + await zeroEx.token.transferFromAsync(tokenAddress, owner, spender, spender, amountToTransfer, { + gasLimit: constants.MAX_TOKEN_TRANSFERFROM_GAS, + }); const newOwnerBalance = await zeroEx.token.getBalanceAsync(tokenAddress, owner); const newSpenderBalance = await zeroEx.token.getBalanceAsync(tokenAddress, spender); @@ -106,7 +114,9 @@ contract('UnlimitedAllowanceToken', (accounts: string[]) => { const amountToTransfer = initOwnerBalance; const initSpenderAllowance = initOwnerBalance; await zeroEx.token.setAllowanceAsync(tokenAddress, owner, spender, initSpenderAllowance); - await zeroEx.token.transferFromAsync(tokenAddress, owner, spender, spender, amountToTransfer); + await zeroEx.token.transferFromAsync(tokenAddress, owner, spender, spender, amountToTransfer, { + gasLimit: constants.MAX_TOKEN_TRANSFERFROM_GAS, + }); const newSpenderAllowance = await zeroEx.token.getAllowanceAsync(tokenAddress, owner, spender); expect(newSpenderAllowance).to.be.bignumber.equal(0); diff --git a/packages/contracts/test/ts/unlimited_allowance_token_v2.ts b/packages/contracts/test/ts/unlimited_allowance_token_v2.ts new file mode 100644 index 000000000..4fa06e483 --- /dev/null +++ b/packages/contracts/test/ts/unlimited_allowance_token_v2.ts @@ -0,0 +1,132 @@ +import {ZeroEx} from '0x.js'; +import {BigNumber} from 'bignumber.js'; +import * as chai from 'chai'; +import * as Web3 from 'web3'; + +import {Artifacts} from '../../util/artifacts'; +import {constants} from '../../util/constants'; +import {ContractInstance} from '../../util/types'; + +import {chaiSetup} from './utils/chai_setup'; + +const {DummyTokenV2} = new Artifacts(artifacts); +const web3: Web3 = (global as any).web3; +chaiSetup.configure(); +const expect = chai.expect; + +contract('UnlimitedAllowanceTokenV2', (accounts: string[]) => { + const config = { + networkId: constants.TESTRPC_NETWORK_ID, + }; + const zeroEx = new ZeroEx(web3.currentProvider, config); + const owner = accounts[0]; + const spender = accounts[1]; + + const MAX_MINT_VALUE = new BigNumber(100000000000000000000); + let tokenAddress: string; + let token: ContractInstance; + + beforeEach(async () => { + token = await DummyTokenV2.new({from: owner}); + await token.mint(MAX_MINT_VALUE, {from: owner}); + tokenAddress = token.address; + }); + + describe('transfer', () => { + it('should throw if owner has insufficient balance', async () => { + const ownerBalance = await zeroEx.token.getBalanceAsync(tokenAddress, owner); + const amountToTransfer = ownerBalance.plus(1); + return expect(token.transfer.call(spender, amountToTransfer, {from: owner})) + .to.be.rejectedWith(constants.REVERT); + }); + + it('should transfer balance from sender to receiver', async () => { + const receiver = spender; + const initOwnerBalance = await zeroEx.token.getBalanceAsync(tokenAddress, owner); + const amountToTransfer = new BigNumber(1); + await zeroEx.token.transferAsync(tokenAddress, owner, receiver, amountToTransfer); + const finalOwnerBalance = await zeroEx.token.getBalanceAsync(tokenAddress, owner); + const finalReceiverBalance = await zeroEx.token.getBalanceAsync(tokenAddress, receiver); + + const expectedFinalOwnerBalance = initOwnerBalance.minus(amountToTransfer); + const expectedFinalReceiverBalance = amountToTransfer; + expect(finalOwnerBalance).to.be.bignumber.equal(expectedFinalOwnerBalance); + expect(finalReceiverBalance).to.be.bignumber.equal(expectedFinalReceiverBalance); + }); + + it('should return true on a 0 value transfer', async () => { + const didReturnTrue = await token.transfer.call(spender, 0, {from: owner}); + expect(didReturnTrue).to.be.true(); + }); + }); + + describe('transferFrom', () => { + it('should throw if owner has insufficient balance', async () => { + const ownerBalance = await zeroEx.token.getBalanceAsync(tokenAddress, owner); + const amountToTransfer = ownerBalance.plus(1); + await zeroEx.token.setAllowanceAsync(tokenAddress, owner, spender, amountToTransfer); + return expect(token.transferFrom.call(owner, spender, amountToTransfer, {from: spender})) + .to.be.rejectedWith(constants.REVERT); + }); + + it('should throw if spender has insufficient allowance', async () => { + const ownerBalance = await zeroEx.token.getBalanceAsync(tokenAddress, owner); + const amountToTransfer = ownerBalance; + + const spenderAllowance = await zeroEx.token.getAllowanceAsync(tokenAddress, owner, spender); + const spenderAllowanceIsInsufficient = spenderAllowance.cmp(amountToTransfer) < 0; + expect(spenderAllowanceIsInsufficient).to.be.true(); + + return expect(token.transferFrom.call(owner, spender, amountToTransfer, {from: spender})) + .to.be.rejectedWith(constants.REVERT); + }); + + it('should return true on a 0 value transfer', async () => { + const amountToTransfer = 0; + const didReturnTrue = await token.transferFrom.call(owner, spender, amountToTransfer, {from: spender}); + expect(didReturnTrue).to.be.true(); + }); + + it('should not modify spender allowance if spender allowance is 2^256 - 1', async () => { + const initOwnerBalance = await zeroEx.token.getBalanceAsync(tokenAddress, owner); + const amountToTransfer = initOwnerBalance; + const initSpenderAllowance = zeroEx.token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS; + await zeroEx.token.setAllowanceAsync(tokenAddress, owner, spender, initSpenderAllowance); + await zeroEx.token.transferFromAsync(tokenAddress, owner, spender, spender, amountToTransfer, { + gasLimit: constants.MAX_TOKEN_TRANSFERFROM_GAS, + }); + + const newSpenderAllowance = await zeroEx.token.getAllowanceAsync(tokenAddress, owner, spender); + expect(initSpenderAllowance).to.be.bignumber.equal(newSpenderAllowance); + }); + + it('should transfer the correct balances if spender has sufficient allowance', async () => { + const initOwnerBalance = await zeroEx.token.getBalanceAsync(tokenAddress, owner); + const amountToTransfer = initOwnerBalance; + const initSpenderAllowance = initOwnerBalance; + await zeroEx.token.setAllowanceAsync(tokenAddress, owner, spender, initSpenderAllowance); + await zeroEx.token.transferFromAsync(tokenAddress, owner, spender, spender, amountToTransfer, { + gasLimit: constants.MAX_TOKEN_TRANSFERFROM_GAS, + }); + + const newOwnerBalance = await zeroEx.token.getBalanceAsync(tokenAddress, owner); + const newSpenderBalance = await zeroEx.token.getBalanceAsync(tokenAddress, spender); + + expect(newOwnerBalance).to.be.bignumber.equal(0); + expect(newSpenderBalance).to.be.bignumber.equal(initOwnerBalance); + }); + + it('should modify allowance if spender has sufficient allowance less than 2^256 - 1', async () => { + const initOwnerBalance = await zeroEx.token.getBalanceAsync(tokenAddress, owner); + const amountToTransfer = initOwnerBalance; + const initSpenderAllowance = initOwnerBalance; + await zeroEx.token.setAllowanceAsync(tokenAddress, owner, spender, initSpenderAllowance); + await zeroEx.token.transferFromAsync(tokenAddress, owner, spender, spender, amountToTransfer, { + gasLimit: constants.MAX_TOKEN_TRANSFERFROM_GAS, + }); + + const newSpenderAllowance = await zeroEx.token.getAllowanceAsync(tokenAddress, owner, spender); + expect(newSpenderAllowance).to.be.bignumber.equal(0); + }); + }); +}); diff --git a/packages/contracts/test/ts/zrxToken.ts b/packages/contracts/test/ts/zrx_token.ts index 471ee93f2..6312056b2 100644 --- a/packages/contracts/test/ts/zrxToken.ts +++ b/packages/contracts/test/ts/zrx_token.ts @@ -4,6 +4,7 @@ import * as chai from 'chai'; import Web3 = require('web3'); import {Artifacts} from '../../util/artifacts'; +import {constants} from '../../util/constants'; import {ContractInstance} from '../../util/types'; import {chaiSetup} from './utils/chai_setup'; @@ -25,9 +26,10 @@ contract('ZRXToken', (accounts: string[]) => { beforeEach(async () => { zeroEx = new ZeroEx(web3.currentProvider, { - exchangeContractAddress: Exchange.address, + exchangeContractAddress: Exchange.address, + networkId: constants.TESTRPC_NETWORK_ID, }); - zrxAddress = await zeroEx.exchange.getZRXTokenAddressAsync(); + zrxAddress = zeroEx.exchange.getZRXTokenAddress(); zrx = await ZRXToken.at(zrxAddress); MAX_UINT = zeroEx.token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS; }); @@ -92,12 +94,14 @@ contract('ZRXToken', (accounts: string[]) => { it('should return false if owner has insufficient balance', async () => { const ownerBalance = await zeroEx.token.getBalanceAsync(zrxAddress, owner); const amountToTransfer = ownerBalance.plus(1); - let txHash = await zeroEx.token.setAllowanceAsync(zrxAddress, owner, spender, amountToTransfer); + let txHash = await zeroEx.token.setAllowanceAsync(zrxAddress, owner, spender, amountToTransfer, + {gasLimit: constants.MAX_TOKEN_APPROVE_GAS}); await zeroEx.awaitTransactionMinedAsync(txHash); const didReturnTrue = await zrx.transferFrom.call(owner, spender, amountToTransfer, {from: spender}); expect(didReturnTrue).to.be.false(); // Reset allowance - txHash = await zeroEx.token.setAllowanceAsync(zrxAddress, owner, spender, new BigNumber(0)); + txHash = await zeroEx.token.setAllowanceAsync(zrxAddress, owner, spender, new BigNumber(0), + {gasLimit: constants.MAX_TOKEN_APPROVE_GAS}); await zeroEx.awaitTransactionMinedAsync(txHash); }); @@ -125,7 +129,8 @@ contract('ZRXToken', (accounts: string[]) => { const initSpenderAllowance = MAX_UINT; let txHash = await zeroEx.token.setAllowanceAsync(zrxAddress, owner, spender, initSpenderAllowance); await zeroEx.awaitTransactionMinedAsync(txHash); - txHash = await zeroEx.token.transferFromAsync(zrxAddress, owner, spender, spender, amountToTransfer); + txHash = await zeroEx.token.transferFromAsync(zrxAddress, owner, spender, spender, amountToTransfer, + {gasLimit: constants.MAX_TOKEN_TRANSFERFROM_GAS}); await zeroEx.awaitTransactionMinedAsync(txHash); const newSpenderAllowance = await zeroEx.token.getAllowanceAsync(zrxAddress, owner, spender); @@ -142,7 +147,8 @@ contract('ZRXToken', (accounts: string[]) => { const initSpenderAllowance = initOwnerBalance; let txHash = await zeroEx.token.setAllowanceAsync(zrxAddress, owner, spender, initSpenderAllowance); await zeroEx.awaitTransactionMinedAsync(txHash); - txHash = await zeroEx.token.transferFromAsync(zrxAddress, owner, spender, spender, amountToTransfer); + txHash = await zeroEx.token.transferFromAsync(zrxAddress, owner, spender, spender, amountToTransfer, + {gasLimit: constants.MAX_TOKEN_TRANSFERFROM_GAS}); await zeroEx.awaitTransactionMinedAsync(txHash); const newOwnerBalance = await zeroEx.token.getBalanceAsync(zrxAddress, owner); @@ -158,7 +164,8 @@ contract('ZRXToken', (accounts: string[]) => { const initSpenderAllowance = initOwnerBalance; let txHash = await zeroEx.token.setAllowanceAsync(zrxAddress, owner, spender, initSpenderAllowance); await zeroEx.awaitTransactionMinedAsync(txHash); - txHash = await zeroEx.token.transferFromAsync(zrxAddress, owner, spender, spender, amountToTransfer); + txHash = await zeroEx.token.transferFromAsync(zrxAddress, owner, spender, spender, amountToTransfer, + {gasLimit: constants.MAX_TOKEN_TRANSFERFROM_GAS}); await zeroEx.awaitTransactionMinedAsync(txHash); const newSpenderAllowance = await zeroEx.token.getAllowanceAsync(zrxAddress, owner, spender); diff --git a/packages/contracts/util/artifacts.ts b/packages/contracts/util/artifacts.ts index b15c9216f..6b05df78c 100644 --- a/packages/contracts/util/artifacts.ts +++ b/packages/contracts/util/artifacts.ts @@ -6,7 +6,9 @@ export class Artifacts { public Exchange: any; public ZRXToken: any; public DummyToken: any; + public DummyTokenV2: any; public EtherToken: any; + public EtherTokenV2: any; public MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress: any; public MaliciousToken: any; constructor(artifacts: any) { @@ -17,7 +19,9 @@ export class Artifacts { this.Exchange = artifacts.require('Exchange'); this.ZRXToken = artifacts.require('ZRXToken'); this.DummyToken = artifacts.require('DummyToken'); + this.DummyTokenV2 = artifacts.require('DummyToken_v2'); this.EtherToken = artifacts.require('EtherToken'); + this.EtherTokenV2 = artifacts.require('EtherToken_v2'); this.MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress = artifacts.require( 'MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress'); this.MaliciousToken = artifacts.require('MaliciousToken'); diff --git a/packages/contracts/util/constants.ts b/packages/contracts/util/constants.ts index 5beebc68c..e61b2f802 100644 --- a/packages/contracts/util/constants.ts +++ b/packages/contracts/util/constants.ts @@ -1,4 +1,9 @@ export const constants = { NULL_BYTES: '0x', INVALID_OPCODE: 'invalid opcode', + REVERT: 'revert', + TESTRPC_NETWORK_ID: 50, + MAX_ETHERTOKEN_WITHDRAW_GAS: 43000, + MAX_TOKEN_TRANSFERFROM_GAS: 80000, + MAX_TOKEN_APPROVE_GAS: 60000, }; diff --git a/packages/subproviders/package.json b/packages/subproviders/package.json index b0c5686a6..8a222457d 100644 --- a/packages/subproviders/package.json +++ b/packages/subproviders/package.json @@ -31,6 +31,7 @@ }, "devDependencies": { "@0xproject/tslint-config": "^0.2.1", + "@0xproject/utils": "^0.1.0", "@types/lodash": "^4.14.86", "@types/mocha": "^2.2.42", "@types/node": "^8.0.53", @@ -2,13 +2,6 @@ # yarn lockfile v1 -"0x-json-schemas@^0.6.1": - version "0.6.6" - resolved "https://registry.yarnpkg.com/0x-json-schemas/-/0x-json-schemas-0.6.6.tgz#3852e639245474a14daa2f8c454ba83ca5df8a9c" - dependencies: - jsonschema "^1.2.0" - lodash.values "^4.3.0" - "0x.js@0.27.1": version "0.27.1" resolved "https://registry.yarnpkg.com/0x.js/-/0x.js-0.27.1.tgz#e0dff70e257efbb7f54dddb55dddf2dce0b971ab" @@ -29,24 +22,6 @@ uuid "^3.1.0" web3 "^0.20.0" -"0x.js@^0.22.6": - version "0.22.6" - resolved "https://registry.yarnpkg.com/0x.js/-/0x.js-0.22.6.tgz#bc3ff79b6d71f8cf7fae3c78b2c776cfa79c193a" - dependencies: - "0x-json-schemas" "^0.6.1" - bignumber.js "^4.1.0" - compare-versions "^3.0.1" - es6-promisify "^5.0.0" - ethereumjs-abi "^0.6.4" - ethereumjs-blockstream "^2.0.6" - ethereumjs-util "^5.1.1" - find-versions "^2.0.0" - js-sha3 "^0.6.1" - lodash "^4.17.4" - publish-release "^1.3.3" - uuid "^3.1.0" - web3 "^0.20.0" - "@0xproject/assert@^0.0.6": version "0.0.6" resolved "https://registry.yarnpkg.com/@0xproject/assert/-/assert-0.0.6.tgz#773616620314f40ace11a9c4c65cc95398d2c178" @@ -112,10 +87,6 @@ version "4.6.2" resolved "https://registry.yarnpkg.com/@types/history/-/history-4.6.2.tgz#12cfaba693ba20f114ed5765467ff25fdf67ddb0" -"@types/isomorphic-fetch@^0.0.34": - version "0.0.34" - resolved "https://registry.yarnpkg.com/@types/isomorphic-fetch/-/isomorphic-fetch-0.0.34.tgz#3c3483e606c041378438e951464f00e4e60706d6" - "@types/jsonschema@^1.1.1": version "1.1.1" resolved "https://registry.yarnpkg.com/@types/jsonschema/-/jsonschema-1.1.1.tgz#08703dfe074010e8e829123111594af731f57b1a" @@ -1287,7 +1258,7 @@ big.js@^3.1.3: version "3.2.0" resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.2.0.tgz#a5fc298b81b9e0dca2e458824784b65c52ba588e" -bignumber.js@^4.0.2, bignumber.js@^4.1.0, bignumber.js@~4.1.0: +bignumber.js@^4.0.2, bignumber.js@~4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-4.1.0.tgz#db6f14067c140bd46624815a7916c92d9b6c24b1" @@ -2662,10 +2633,14 @@ diff@3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/diff/-/diff-3.2.0.tgz#c9ce393a4b7cbd0b058a725c93df299027868ff9" -diff@3.3.1, diff@^3.1.0, diff@^3.2.0: +diff@3.3.1, diff@^3.2.0: version "3.3.1" resolved "https://registry.yarnpkg.com/diff/-/diff-3.3.1.tgz#aa8567a6eed03c531fc89d3f711cd0e5259dec75" +diff@^3.1.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-3.4.0.tgz#b1d85507daf3964828de54b37d0d73ba67dda56c" + diffie-hellman@^5.0.0: version "5.0.2" resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.2.tgz#b5835739270cfe26acf632099fded2a07f209e5e" @@ -5076,8 +5051,8 @@ lolex@^1.6.0: resolved "https://registry.yarnpkg.com/lolex/-/lolex-1.6.0.tgz#3a9a0283452a47d7439e72731b9e07d7386e49f6" lolex@^2.2.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/lolex/-/lolex-2.3.0.tgz#d6bad0f0aa5caebffcfebb09fb2caa89baaff51c" + version "2.3.1" + resolved "https://registry.yarnpkg.com/lolex/-/lolex-2.3.1.tgz#3d2319894471ea0950ef64692ead2a5318cff362" longest@^1.0.1: version "1.0.1" @@ -6472,7 +6447,7 @@ public-encrypt@^4.0.0: parse-asn1 "^5.0.0" randombytes "^2.0.1" -publish-release@0xproject/publish-release, publish-release@^1.3.3: +publish-release@0xproject/publish-release: version "1.3.3" resolved "https://codeload.github.com/0xproject/publish-release/tar.gz/c67c546726deecabd0cb35f9873afc912f862bd3" dependencies: @@ -7585,17 +7560,7 @@ sockjs@0.3.18: faye-websocket "^0.10.0" uuid "^2.0.2" -solc@0.4.11: - version "0.4.11" - resolved "https://registry.yarnpkg.com/solc/-/solc-0.4.11.tgz#2522eb43e7c0419bac2060b96e20a2593bfb5e8b" - dependencies: - fs-extra "^0.30.0" - memorystream "^0.3.1" - require-from-string "^1.1.0" - semver "^5.3.0" - yargs "^4.7.1" - -solc@^0.4.18, solc@^0.4.2: +solc@0.4.18, solc@^0.4.18, solc@^0.4.2: version "0.4.18" resolved "https://registry.yarnpkg.com/solc/-/solc-0.4.18.tgz#83ac6d871dd16a9710e67dbb76dad7f614100702" dependencies: @@ -8289,13 +8254,13 @@ truffle-hdwallet-provider@^0.0.3: web3 "^0.18.2" web3-provider-engine "^8.4.0" -truffle@3.4.3: - version "3.4.3" - resolved "https://registry.yarnpkg.com/truffle/-/truffle-3.4.3.tgz#6d9ea4abea758b452b2d3769669eb7109146229e" +truffle@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/truffle/-/truffle-4.0.1.tgz#d8661a4ad7a6ca094b7517d29b199c60e6dde665" dependencies: mocha "^3.4.2" original-require "^1.0.1" - solc "0.4.11" + solc "0.4.18" tslib@^1.7.1: version "1.8.0" |