@0x/contracts-asset-proxy
: Use LibERC20Token
in UniswapBridge
and Eth2DaiBridge
.
This commit is contained in:
parent
c8ef10baaf
commit
0f3610c92a
@ -21,6 +21,7 @@ pragma experimental ABIEncoderV2;
|
|||||||
|
|
||||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
|
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
|
||||||
import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol";
|
import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol";
|
||||||
|
import "@0x/contracts-utils/contracts/src/LibERC20Token.sol";
|
||||||
import "../interfaces/IERC20Bridge.sol";
|
import "../interfaces/IERC20Bridge.sol";
|
||||||
import "../interfaces/IEth2Dai.sol";
|
import "../interfaces/IEth2Dai.sol";
|
||||||
|
|
||||||
@ -57,7 +58,7 @@ contract Eth2DaiBridge is
|
|||||||
|
|
||||||
IEth2Dai exchange = _getEth2DaiContract();
|
IEth2Dai exchange = _getEth2DaiContract();
|
||||||
// Grant an allowance to the exchange to spend `fromTokenAddress` token.
|
// 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.
|
// Try to sell all of this contract's `fromTokenAddress` token balance.
|
||||||
uint256 boughtAmount = _getEth2DaiContract().sellAllAmount(
|
uint256 boughtAmount = _getEth2DaiContract().sellAllAmount(
|
||||||
@ -67,7 +68,7 @@ contract Eth2DaiBridge is
|
|||||||
amount
|
amount
|
||||||
);
|
);
|
||||||
// Transfer the converted `toToken`s to `to`.
|
// Transfer the converted `toToken`s to `to`.
|
||||||
_transferERC20Token(toTokenAddress, to, boughtAmount);
|
LibERC20Token.transfer(toTokenAddress, to, boughtAmount);
|
||||||
return BRIDGE_SUCCESS;
|
return BRIDGE_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,49 +95,4 @@ contract Eth2DaiBridge is
|
|||||||
{
|
{
|
||||||
return IEth2Dai(ETH2DAI_ADDRESS);
|
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");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@ pragma experimental ABIEncoderV2;
|
|||||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
|
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
|
||||||
import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol";
|
import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol";
|
||||||
import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol";
|
import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol";
|
||||||
|
import "@0x/contracts-utils/contracts/src/LibERC20Token.sol";
|
||||||
import "../interfaces/IUniswapExchangeFactory.sol";
|
import "../interfaces/IUniswapExchangeFactory.sol";
|
||||||
import "../interfaces/IUniswapExchange.sol";
|
import "../interfaces/IUniswapExchange.sol";
|
||||||
import "../interfaces/IERC20Bridge.sol";
|
import "../interfaces/IERC20Bridge.sol";
|
||||||
@ -77,7 +78,7 @@ contract UniswapBridge is
|
|||||||
|
|
||||||
// Just transfer the tokens if they're the same.
|
// Just transfer the tokens if they're the same.
|
||||||
if (fromTokenAddress == toTokenAddress) {
|
if (fromTokenAddress == toTokenAddress) {
|
||||||
IERC20Token(fromTokenAddress).transfer(to, amount);
|
LibERC20Token.transfer(fromTokenAddress, to, amount);
|
||||||
return BRIDGE_SUCCESS;
|
return BRIDGE_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -189,7 +190,7 @@ contract UniswapBridge is
|
|||||||
function _grantExchangeAllowance(IUniswapExchange exchange, address tokenAddress)
|
function _grantExchangeAllowance(IUniswapExchange exchange, address tokenAddress)
|
||||||
private
|
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.
|
/// @dev Retrieves the uniswap exchange for a given token pair.
|
||||||
|
@ -11,7 +11,7 @@ import {
|
|||||||
TransactionHelper,
|
TransactionHelper,
|
||||||
} from '@0x/contracts-test-utils';
|
} from '@0x/contracts-test-utils';
|
||||||
import { AssetProxyId } from '@0x/types';
|
import { AssetProxyId } from '@0x/types';
|
||||||
import { BigNumber } from '@0x/utils';
|
import { BigNumber, RawRevertError } from '@0x/utils';
|
||||||
import { DecodedLogs } from 'ethereum-types';
|
import { DecodedLogs } from 'ethereum-types';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
@ -179,14 +179,14 @@ blockchainTests.resets('Eth2DaiBridge unit tests', env => {
|
|||||||
return expect(tx).to.revertWith(opts.toTokentransferRevertReason);
|
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 opts = createWithdrawToOpts({ toTokenTransferReturnData: hexLeftPad(0) });
|
||||||
const tx = withdrawToAsync(opts);
|
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 () => {
|
it('succeeds if `toTokenAddress.transfer()` returns true', async () => {
|
||||||
await withdrawToAsync({ toTokenTransferReturnData: hexLeftPad(100) });
|
await withdrawToAsync({ toTokenTransferReturnData: hexLeftPad(1) });
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user