@0x/contracts-asset-proxy: Use LibERC20Token in UniswapBridge and Eth2DaiBridge.

This commit is contained in:
Lawrence Forman 2019-10-31 10:32:09 -04:00
parent c8ef10baaf
commit 0f3610c92a
3 changed files with 11 additions and 54 deletions

View File

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

View File

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

View File

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