diff --git a/contracts/asset-proxy/contracts/src/bridges/Eth2DaiBridge.sol b/contracts/asset-proxy/contracts/src/bridges/Eth2DaiBridge.sol index d3860db42b..3c4b3e634f 100644 --- a/contracts/asset-proxy/contracts/src/bridges/Eth2DaiBridge.sol +++ b/contracts/asset-proxy/contracts/src/bridges/Eth2DaiBridge.sol @@ -21,6 +21,7 @@ pragma experimental ABIEncoderV2; import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol"; +import "@0x/contracts-utils/contracts/src/LibERC20Token.sol"; import "../interfaces/IERC20Bridge.sol"; import "../interfaces/IEth2Dai.sol"; @@ -57,7 +58,7 @@ contract Eth2DaiBridge is IEth2Dai exchange = _getEth2DaiContract(); // Grant an allowance to the exchange to spend `fromTokenAddress` token. - IERC20Token(fromTokenAddress).approve(address(exchange), uint256(-1)); + LibERC20Token.approve(fromTokenAddress, address(exchange), uint256(-1)); // Try to sell all of this contract's `fromTokenAddress` token balance. uint256 boughtAmount = _getEth2DaiContract().sellAllAmount( @@ -67,7 +68,7 @@ contract Eth2DaiBridge is amount ); // Transfer the converted `toToken`s to `to`. - _transferERC20Token(toTokenAddress, to, boughtAmount); + LibERC20Token.transfer(toTokenAddress, to, boughtAmount); return BRIDGE_SUCCESS; } @@ -94,49 +95,4 @@ contract Eth2DaiBridge is { return IEth2Dai(ETH2DAI_ADDRESS); } - - /// @dev Permissively transfers an ERC20 token that may not adhere to - /// specs. - /// @param tokenAddress The token contract address. - /// @param to The token recipient. - /// @param amount The amount of tokens to transfer. - function _transferERC20Token( - address tokenAddress, - address to, - uint256 amount - ) - private - { - // Transfer tokens. - // We do a raw call so we can check the success separate - // from the return data. - (bool didSucceed, bytes memory returnData) = tokenAddress.call( - abi.encodeWithSelector( - IERC20Token(0).transfer.selector, - to, - amount - ) - ); - if (!didSucceed) { - assembly { revert(add(returnData, 0x20), mload(returnData)) } - } - - // Check return data. - // If there is no return data, we assume the token incorrectly - // does not return a bool. In this case we expect it to revert - // on failure, which was handled above. - // If the token does return data, we require that it is a single - // value that evaluates to true. - assembly { - if returndatasize { - didSucceed := 0 - if eq(returndatasize, 32) { - // First 64 bytes of memory are reserved scratch space - returndatacopy(0, 0, 32) - didSucceed := mload(0) - } - } - } - require(didSucceed, "ERC20_TRANSFER_FAILED"); - } } diff --git a/contracts/asset-proxy/contracts/src/bridges/UniswapBridge.sol b/contracts/asset-proxy/contracts/src/bridges/UniswapBridge.sol index 1eb674109f..587882a21f 100644 --- a/contracts/asset-proxy/contracts/src/bridges/UniswapBridge.sol +++ b/contracts/asset-proxy/contracts/src/bridges/UniswapBridge.sol @@ -22,6 +22,7 @@ pragma experimental ABIEncoderV2; import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol"; import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol"; +import "@0x/contracts-utils/contracts/src/LibERC20Token.sol"; import "../interfaces/IUniswapExchangeFactory.sol"; import "../interfaces/IUniswapExchange.sol"; import "../interfaces/IERC20Bridge.sol"; @@ -77,7 +78,7 @@ contract UniswapBridge is // Just transfer the tokens if they're the same. if (fromTokenAddress == toTokenAddress) { - IERC20Token(fromTokenAddress).transfer(to, amount); + LibERC20Token.transfer(fromTokenAddress, to, amount); return BRIDGE_SUCCESS; } @@ -189,7 +190,7 @@ contract UniswapBridge is function _grantExchangeAllowance(IUniswapExchange exchange, address tokenAddress) private { - IERC20Token(tokenAddress).approve(address(exchange), uint256(-1)); + LibERC20Token.approve(tokenAddress, address(exchange), uint256(-1)); } /// @dev Retrieves the uniswap exchange for a given token pair. diff --git a/contracts/asset-proxy/test/eth2dai_bridge.ts b/contracts/asset-proxy/test/eth2dai_bridge.ts index 46829436c5..2cf0173239 100644 --- a/contracts/asset-proxy/test/eth2dai_bridge.ts +++ b/contracts/asset-proxy/test/eth2dai_bridge.ts @@ -11,7 +11,7 @@ import { TransactionHelper, } from '@0x/contracts-test-utils'; import { AssetProxyId } from '@0x/types'; -import { BigNumber } from '@0x/utils'; +import { BigNumber, RawRevertError } from '@0x/utils'; import { DecodedLogs } from 'ethereum-types'; import * as _ from 'lodash'; @@ -179,14 +179,14 @@ blockchainTests.resets('Eth2DaiBridge unit tests', env => { return expect(tx).to.revertWith(opts.toTokentransferRevertReason); }); - it('fails if `toTokenAddress.transfer()` returns falsey', async () => { + it('fails if `toTokenAddress.transfer()` returns false', async () => { const opts = createWithdrawToOpts({ toTokenTransferReturnData: hexLeftPad(0) }); const tx = withdrawToAsync(opts); - return expect(tx).to.revertWith('ERC20_TRANSFER_FAILED'); + return expect(tx).to.revertWith(new RawRevertError(hexLeftPad(0))); }); - it('succeeds if `toTokenAddress.transfer()` returns truthy', async () => { - await withdrawToAsync({ toTokenTransferReturnData: hexLeftPad(100) }); + it('succeeds if `toTokenAddress.transfer()` returns true', async () => { + await withdrawToAsync({ toTokenTransferReturnData: hexLeftPad(1) }); }); }); });