add ERC20Bridge buy support
This commit is contained in:
@@ -32,13 +32,13 @@ contract Forwarder is
|
||||
{
|
||||
constructor (
|
||||
address _exchange,
|
||||
bytes memory _wethAssetData
|
||||
address _weth
|
||||
)
|
||||
public
|
||||
Ownable()
|
||||
LibConstants(
|
||||
_exchange,
|
||||
_wethAssetData
|
||||
_weth
|
||||
)
|
||||
MixinForwarderCore()
|
||||
{}
|
||||
|
@@ -21,7 +21,6 @@ pragma solidity ^0.5.9;
|
||||
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
|
||||
import "@0x/contracts-utils/contracts/src/LibRichErrors.sol";
|
||||
import "@0x/contracts-utils/contracts/src/Ownable.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
|
||||
import "@0x/contracts-erc721/contracts/src/interfaces/IERC721Token.sol";
|
||||
import "./libs/LibConstants.sol";
|
||||
@@ -36,13 +35,10 @@ contract MixinAssets is
|
||||
{
|
||||
using LibBytes for bytes;
|
||||
|
||||
bytes4 constant internal ERC20_TRANSFER_SELECTOR = bytes4(keccak256("transfer(address,uint256)"));
|
||||
|
||||
/// @dev Withdraws assets from this contract. The contract formerly required a ZRX balance in order
|
||||
/// to function optimally, and this function allows the ZRX to be withdrawn by owner.
|
||||
/// It may also be used to withdraw assets that were accidentally sent to this contract.
|
||||
/// @dev Withdraws assets from this contract. It may be used by the owner to withdraw assets
|
||||
/// that were accidentally sent to this contract.
|
||||
/// @param assetData Byte array encoded for the respective asset proxy.
|
||||
/// @param amount Amount of ERC20 token to withdraw.
|
||||
/// @param amount Amount of the asset to withdraw.
|
||||
function withdrawAsset(
|
||||
bytes calldata assetData,
|
||||
uint256 amount
|
||||
@@ -64,13 +60,13 @@ contract MixinAssets is
|
||||
{
|
||||
bytes4 proxyId = assetData.readBytes4(0);
|
||||
// For now we only care about ERC20, since percentage fees on ERC721 tokens are invalid.
|
||||
if (proxyId == ERC20_DATA_ID) {
|
||||
address proxyAddress = EXCHANGE.getAssetProxy(ERC20_DATA_ID);
|
||||
if (proxyId == ERC20_PROXY_ID) {
|
||||
address proxyAddress = EXCHANGE.getAssetProxy(ERC20_PROXY_ID);
|
||||
if (proxyAddress == address(0)) {
|
||||
LibRichErrors.rrevert(LibForwarderRichErrors.UnregisteredAssetProxyError());
|
||||
}
|
||||
IERC20Token assetToken = IERC20Token(assetData.readAddress(16));
|
||||
assetToken.approve(proxyAddress, MAX_UINT);
|
||||
address token = assetData.readAddress(16);
|
||||
LibERC20Token.approve(token, proxyAddress, MAX_UINT);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,10 +81,12 @@ contract MixinAssets is
|
||||
{
|
||||
bytes4 proxyId = assetData.readBytes4(0);
|
||||
|
||||
if (proxyId == ERC20_DATA_ID) {
|
||||
if (proxyId == ERC20_PROXY_ID) {
|
||||
_transferERC20Token(assetData, amount);
|
||||
} else if (proxyId == ERC721_DATA_ID) {
|
||||
} else if (proxyId == ERC721_PROXY_ID) {
|
||||
_transferERC721Token(assetData, amount);
|
||||
} else if (proxyId == ERC20_BRIDGE_PROXY_ID) {
|
||||
_transferERC20BridgeAsset(assetData, amount);
|
||||
} else {
|
||||
LibRichErrors.rrevert(LibForwarderRichErrors.UnsupportedAssetProxyError(
|
||||
proxyId
|
||||
@@ -135,4 +133,18 @@ contract MixinAssets is
|
||||
tokenId
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Decodes ERC20Bridge assetData and transfers given amount to sender.
|
||||
/// @param assetData Byte array encoded for the respective asset proxy.
|
||||
/// @param amount Amount of asset to transfer to sender.
|
||||
function _transferERC20BridgeAsset(
|
||||
bytes memory assetData,
|
||||
uint256 amount
|
||||
)
|
||||
internal
|
||||
{
|
||||
address token = assetData.readAddress(16);
|
||||
// Transfer tokens.
|
||||
LibERC20Token.transfer(token, msg.sender, amount);
|
||||
}
|
||||
}
|
||||
|
@@ -88,7 +88,7 @@ contract MixinExchangeWrapper is
|
||||
)
|
||||
{
|
||||
// No taker fee or percentage fee
|
||||
if (order.takerFee == 0 || order.takerFeeAssetData.equals(order.makerAssetData)) {
|
||||
if (order.takerFee == 0 || _isPercentageFee(order.takerFeeAssetData, order.makerAssetData)) {
|
||||
// Attempt to sell the remaining amount of WETH
|
||||
LibFillResults.FillResults memory singleFillResults = _fillOrderNoThrow(
|
||||
order,
|
||||
@@ -228,7 +228,7 @@ contract MixinExchangeWrapper is
|
||||
|
||||
makerAssetAcquiredAmount = singleFillResults.makerAssetFilledAmount;
|
||||
// Percentage fee
|
||||
} else if (order.takerFeeAssetData.equals(order.makerAssetData)) {
|
||||
} else if (_isPercentageFee(order.takerFeeAssetData, order.makerAssetData)) {
|
||||
// Calculate the remaining amount of takerAsset to sell
|
||||
uint256 remainingTakerAssetFillAmount = LibMath.getPartialAmountCeil(
|
||||
order.takerAssetAmount,
|
||||
@@ -316,4 +316,40 @@ contract MixinExchangeWrapper is
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Checks whether an order's taker fee is effectively denominated in the maker asset.
|
||||
/// This is the case if they have the same ERC20Proxy asset data, or if the makerAssetData
|
||||
/// is the ERC20Bridge equivalent of the takerFeeAssetData.
|
||||
/// @param takerFeeAssetData Byte array encoded for the takerFee asset proxy.
|
||||
/// @param makerAssetData Byte array encoded for the maker asset proxy.
|
||||
/// @return isPercentageFee Whether or not the taker fee asset matches the maker asset.
|
||||
function _isPercentageFee(
|
||||
bytes memory takerFeeAssetData,
|
||||
bytes memory makerAssetData
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (bool)
|
||||
{
|
||||
bytes4 takerFeeAssetProxyId = takerFeeAssetData.readBytes4(0);
|
||||
// If the takerFee asset is not ERC20, it cannot be a percentage fee (and will revert with
|
||||
// an UnsupportedFeeError in the calling function).
|
||||
if (takerFeeAssetProxyId != ERC20_PROXY_ID) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bytes4 makerAssetProxyId = makerAssetData.readBytes4(0);
|
||||
if (makerAssetProxyId == ERC20_PROXY_ID) {
|
||||
// If the maker asset is ERC20, we can directly compare the asset data.
|
||||
return takerFeeAssetData.equals(makerAssetData);
|
||||
} else if (makerAssetProxyId == ERC20_BRIDGE_PROXY_ID) {
|
||||
// If the maker asset is from an ERC20Bridge, compare the underlying token addresses.
|
||||
address takerFeeToken = takerFeeAssetData.readAddress(16);
|
||||
address makerToken = makerAssetData.readAddress(16);
|
||||
return (takerFeeToken == makerToken);
|
||||
} else {
|
||||
// If the maker asset is of any other type, the taker fee cannot be a percentage fee.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -46,7 +46,7 @@ contract MixinForwarderCore is
|
||||
constructor ()
|
||||
public
|
||||
{
|
||||
address proxyAddress = EXCHANGE.getAssetProxy(ERC20_DATA_ID);
|
||||
address proxyAddress = EXCHANGE.getAssetProxy(ERC20_PROXY_ID);
|
||||
if (proxyAddress == address(0)) {
|
||||
LibRichErrors.rrevert(LibForwarderRichErrors.UnregisteredAssetProxyError());
|
||||
}
|
||||
|
@@ -27,8 +27,10 @@ contract LibConstants {
|
||||
|
||||
using LibBytes for bytes;
|
||||
|
||||
bytes4 constant internal ERC20_DATA_ID = bytes4(keccak256("ERC20Token(address)"));
|
||||
bytes4 constant internal ERC721_DATA_ID = bytes4(keccak256("ERC721Token(address,uint256)"));
|
||||
bytes4 constant internal ERC20_PROXY_ID = bytes4(keccak256("ERC20Token(address)"));
|
||||
bytes4 constant internal ERC721_PROXY_ID = bytes4(keccak256("ERC721Token(address,uint256)"));
|
||||
bytes4 constant internal ERC20_BRIDGE_PROXY_ID = bytes4(keccak256("ERC20Bridge(address,address,bytes)"));
|
||||
|
||||
uint256 constant internal MAX_UINT = 2**256 - 1;
|
||||
uint256 constant internal PERCENTAGE_DENOMINATOR = 10**18;
|
||||
uint256 constant internal MAX_FEE_PERCENTAGE = 5 * PERCENTAGE_DENOMINATOR / 100; // 5%
|
||||
@@ -36,19 +38,15 @@ contract LibConstants {
|
||||
// solhint-disable var-name-mixedcase
|
||||
IExchange internal EXCHANGE;
|
||||
IEtherToken internal ETHER_TOKEN;
|
||||
bytes internal WETH_ASSET_DATA;
|
||||
// solhint-enable var-name-mixedcase
|
||||
|
||||
constructor (
|
||||
address _exchange,
|
||||
bytes memory _wethAssetData
|
||||
address _weth
|
||||
)
|
||||
public
|
||||
{
|
||||
EXCHANGE = IExchange(_exchange);
|
||||
WETH_ASSET_DATA = _wethAssetData;
|
||||
|
||||
address etherToken = _wethAssetData.readAddress(16);
|
||||
ETHER_TOKEN = IEtherToken(etherToken);
|
||||
ETHER_TOKEN = IEtherToken(_weth);
|
||||
}
|
||||
}
|
||||
|
@@ -18,8 +18,6 @@
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
|
||||
import "@0x/contracts-utils/contracts/src/LibRichErrors.sol";
|
||||
|
||||
|
||||
library LibForwarderRichErrors {
|
||||
|
||||
|
Reference in New Issue
Block a user