Merge pull request #255 from 0xProject/feature/updateWeth

Update WETH
This commit is contained in:
Amir Bandeali
2017-12-12 15:39:29 -08:00
committed by GitHub
44 changed files with 909 additions and 185 deletions

View File

@@ -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
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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];
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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];
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}

View File

@@ -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));
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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 {
}
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -1,4 +1,4 @@
pragma solidity 0.4.11;
pragma solidity ^0.4.11;
/*
* Ownable
@@ -25,3 +25,4 @@ contract Ownable {
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -5,7 +5,7 @@ export const constants = {
jsonrpcPort: 8545,
optimizerEnabled: 0,
gasPrice: new BigNumber(20000000000),
timeoutMs: 12000,
timeoutMs: 20000,
zrxTokenAddress: '0xe41d2489571d322189246dafa5ebde1f4699f498',
tokenTransferProxyAddress: '0x8da0d80f5007ef1e431dd2127178d224e32c2ef4',
};

View File

@@ -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([

View File

@@ -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",

View File

@@ -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);

View File

@@ -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));
});
});
});

View File

@@ -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 () => {

View File

@@ -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);
});
});

View File

@@ -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 () => {

View File

@@ -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);
});
});
});

View File

@@ -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);
});
});

View File

@@ -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);
});
});

View File

@@ -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 () => {

View File

@@ -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);

View File

@@ -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);
});
});
});

View File

@@ -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);

View File

@@ -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');

View File

@@ -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,
};

View File

@@ -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",

View File

@@ -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"