aboutsummaryrefslogtreecommitdiffstats
path: root/packages
diff options
context:
space:
mode:
Diffstat (limited to 'packages')
-rw-r--r--packages/contracts/contracts/Exchange.sol7
-rw-r--r--packages/contracts/contracts/TokenRegistry.sol5
-rw-r--r--packages/contracts/contracts/TokenTransferProxy.sol7
-rw-r--r--packages/contracts/contracts/base/SafeMath.sol41
-rw-r--r--packages/contracts/contracts/multisig/MultiSigWallet.sol (renamed from packages/contracts/contracts/base/MultiSigWallet.sol)3
-rw-r--r--packages/contracts/contracts/multisig/MultiSigWalletWithTimeLock.sol (renamed from packages/contracts/contracts/MultiSigWalletWithTimeLock.sol)5
-rw-r--r--packages/contracts/contracts/multisig/MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress.sol (renamed from packages/contracts/contracts/MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress.sol)3
-rw-r--r--packages/contracts/contracts/test/DummyToken.sol9
-rw-r--r--packages/contracts/contracts/test/DummyToken_v2.sol38
-rw-r--r--packages/contracts/contracts/test/MaliciousToken.sol9
-rw-r--r--packages/contracts/contracts/test/Mintable.sol9
-rw-r--r--packages/contracts/contracts/test/Mintable_v2.sol19
-rw-r--r--packages/contracts/contracts/tokens/ERC20Token.sol59
-rw-r--r--packages/contracts/contracts/tokens/EtherToken.sol5
-rw-r--r--packages/contracts/contracts/tokens/EtherToken_v2.sol60
-rw-r--r--packages/contracts/contracts/tokens/StandardToken.sol (renamed from packages/contracts/contracts/base/StandardToken.sol)3
-rw-r--r--packages/contracts/contracts/tokens/Token.sol (renamed from packages/contracts/contracts/base/Token.sol)3
-rw-r--r--packages/contracts/contracts/tokens/Token_v2.sol39
-rw-r--r--packages/contracts/contracts/tokens/UnlimitedAllowanceToken.sol5
-rw-r--r--packages/contracts/contracts/tokens/UnlimitedAllowanceToken_v2.sol47
-rw-r--r--packages/contracts/contracts/tokens/ZRXToken.sol3
-rw-r--r--packages/contracts/contracts/utils/Ownable.sol (renamed from packages/contracts/contracts/base/Ownable.sol)3
-rw-r--r--packages/contracts/contracts/utils/Ownable_v2.sol33
-rw-r--r--packages/contracts/contracts/utils/SafeMath.sol74
-rw-r--r--packages/contracts/contracts/utils/SafeMath_v2.sol74
-rw-r--r--packages/contracts/deploy/test/util/constants.ts2
-rw-r--r--packages/contracts/migrations/2_deploy_independent_contracts.ts9
-rw-r--r--packages/contracts/package.json6
-rw-r--r--packages/contracts/test/ts/ether_token.ts11
-rw-r--r--packages/contracts/test/ts/ether_token_v2.ts168
-rw-r--r--packages/contracts/test/ts/exchange/core.ts29
-rw-r--r--packages/contracts/test/ts/exchange/wrapper.ts8
-rw-r--r--packages/contracts/test/ts/multi_sig_with_time_lock.ts6
-rw-r--r--packages/contracts/test/ts/multi_sig_with_time_lock_except_remove_auth_addr.ts10
-rw-r--r--packages/contracts/test/ts/token_registry.ts28
-rw-r--r--packages/contracts/test/ts/token_transfer_proxy/auth.ts8
-rw-r--r--packages/contracts/test/ts/token_transfer_proxy/transfer_from.ts2
-rw-r--r--packages/contracts/test/ts/unlimited_allowance_token.ts (renamed from packages/contracts/test/ts/unlimitedAllowanceToken.ts)18
-rw-r--r--packages/contracts/test/ts/unlimited_allowance_token_v2.ts132
-rw-r--r--packages/contracts/test/ts/zrx_token.ts (renamed from packages/contracts/test/ts/zrxToken.ts)21
-rw-r--r--packages/contracts/util/artifacts.ts4
-rw-r--r--packages/contracts/util/constants.ts5
-rw-r--r--packages/subproviders/package.json1
43 files changed, 895 insertions, 136 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",