Forwarder StaticCall and MultiAsset buy support

This commit is contained in:
Michael Zhu 2019-12-16 11:23:48 -08:00 committed by Amir
parent 8b27380feb
commit 2b8c6dc8f9
2 changed files with 52 additions and 7 deletions

View File

@ -20,6 +20,7 @@ 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/LibSafeMath.sol";
import "@0x/contracts-utils/contracts/src/Ownable.sol";
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
import "@0x/contracts-erc721/contracts/src/interfaces/IERC721Token.sol";
@ -35,6 +36,7 @@ contract MixinAssets is
IAssets
{
using LibBytes for bytes;
using LibSafeMath for uint256;
/// @dev Withdraws assets from this contract. It may be used by the owner to withdraw assets
/// that were accidentally sent to this contract.
@ -95,7 +97,9 @@ contract MixinAssets is
_transferERC20Token(assetData, amount);
} else if (proxyId == IAssetData(address(0)).ERC721Token.selector) {
_transferERC721Token(assetData, amount);
} else {
} else if (proxyId == IAssetData(address(0)).MultiAsset.selector) {
_transferMultiAsset(assetData, amount);
} else if (proxyId != IAssetData(address(0)).StaticCall.selector) {
LibRichErrors.rrevert(LibForwarderRichErrors.UnsupportedAssetProxyError(
proxyId
));
@ -141,4 +145,23 @@ contract MixinAssets is
tokenId
);
}
function _transferMultiAsset(
bytes memory assetData,
uint256 amount
)
internal
{
// solhint-disable indent
(uint256[] memory nestedAmounts, bytes[] memory nestedAssetData) = abi.decode(
assetData.slice(4, assetData.length),
(uint256[], bytes[])
);
// solhint-enable indent
uint256 numNestedAssets = nestedAssetData.length;
for (uint256 i = 0; i != numNestedAssets; i++) {
_transferAssetToSender(nestedAssetData[i], amount.safeMul(nestedAmounts[i]));
}
}
}

View File

@ -88,9 +88,10 @@ contract MixinExchangeWrapper is
uint256 makerAssetAcquiredAmount
)
{
bool noTakerFee = _noTakerFee(order.takerFee, order.takerFeeAssetData);
// No taker fee or percentage fee
if (
order.takerFee == 0 ||
noTakerFee ||
_areUnderlyingAssetsEqual(order.takerFeeAssetData, order.makerAssetData)
) {
// Attempt to sell the remaining amount of WETH
@ -105,7 +106,7 @@ contract MixinExchangeWrapper is
// Subtract fee from makerAssetFilledAmount for the net amount acquired.
makerAssetAcquiredAmount = singleFillResults.makerAssetFilledAmount
.safeSub(singleFillResults.takerFeePaid);
.safeSub(noTakerFee ? 0 : singleFillResults.takerFeePaid);
// WETH fee
} else if (_areUnderlyingAssetsEqual(order.takerFeeAssetData, order.takerAssetData)) {
@ -230,9 +231,10 @@ contract MixinExchangeWrapper is
uint256 makerAssetAcquiredAmount
)
{
bool noTakerFee = _noTakerFee(order.takerFee, order.takerFeeAssetData);
// No taker fee or WETH fee
if (
order.takerFee == 0 ||
noTakerFee ||
_areUnderlyingAssetsEqual(order.takerFeeAssetData, order.takerAssetData)
) {
// Calculate the remaining amount of takerAsset to sell
@ -251,7 +253,7 @@ contract MixinExchangeWrapper is
// WETH is also spent on the protocol and taker fees, so we add it here.
wethSpentAmount = singleFillResults.takerAssetFilledAmount
.safeAdd(singleFillResults.takerFeePaid)
.safeAdd(noTakerFee ? 0 : singleFillResults.takerFeePaid)
.safeAdd(singleFillResults.protocolFeePaid);
makerAssetAcquiredAmount = singleFillResults.makerAssetFilledAmount;
@ -480,7 +482,7 @@ contract MixinExchangeWrapper is
address token2 = assetData2.readAddress(16);
return (token1 == token2);
} else {
return false;
return assetData1.equals(assetData2);
}
}
@ -494,4 +496,24 @@ contract MixinExchangeWrapper is
{
return order.makerFeeAssetData.length > 3 && order.makerFeeAssetData.readBytes4(0) == EXCHANGE_V2_ORDER_ID;
}
/// @dev Checks whether one asset is effectively equal to another asset.
/// This is the case if they have the same ERC20Proxy/ERC20BridgeProxy asset data, or if
/// one is the ERC20Bridge equivalent of the other.
/// @param takerFee Byte array encoded for the takerFee asset proxy.
/// @param takerFeeAssetData Byte array encoded for the maker asset proxy.
/// @return Whether or not the underlying assets are equal.
function _noTakerFee(
uint256 takerFee,
bytes memory takerFeeAssetData
)
internal
pure
returns (bool)
{
return (
takerFee == 0 ||
takerFeeAssetData.readBytes4(0) == IAssetData(address(0)).StaticCall.selector
);
}
}