slightly restructure contracts to fix bug in the WETH-fee case

This commit is contained in:
Michael Zhu 2019-07-12 14:48:53 -07:00
parent 7ff7e9d2e7
commit 1b8a9e16e2
3 changed files with 93 additions and 49 deletions

View File

@ -89,11 +89,13 @@ contract MixinExchangeWrapper is
bytes[] memory signatures bytes[] memory signatures
) )
internal internal
returns (FillResults memory totalFillResults) returns (
FillResults memory totalFillResults,
uint256 wethSpentAmount,
uint256 makerAssetAcquiredAmount
)
{ {
uint256 ordersLength = orders.length; uint256 ordersLength = orders.length;
// The remaining amount of WETH to sell
uint256 remainingTakerAssetFillAmount = wethSellAmount;
for (uint256 i = 0; i != ordersLength; i++) { for (uint256 i = 0; i != ordersLength; i++) {
require( require(
@ -101,34 +103,62 @@ contract MixinExchangeWrapper is
"MAKER_ASSET_MISMATCH" "MAKER_ASSET_MISMATCH"
); );
// The remaining amount of WETH to sell
uint256 remainingTakerAssetFillAmount = _safeSub(
wethSellAmount,
wethSpentAmount
);
FillResults memory singleFillResults;
// Update amounts filled and the remaining amount of WETH to sell
if (orders[i].makerAssetData.equals(orders[i].takerFeeAssetData)) {
// Attempt to sell the remaining amount of WETH // Attempt to sell the remaining amount of WETH
FillResults memory singleFillResults = _fillOrderNoThrow( singleFillResults = _fillOrderNoThrow(
orders[i], orders[i],
remainingTakerAssetFillAmount, remainingTakerAssetFillAmount,
signatures[i] signatures[i]
); );
// Update amounts filled and the remaining amount of WETH to sell makerAssetAcquiredAmount = _safeAdd(
if (orders[i].makerAssetData.equals(orders[i].takerFeeAssetData)) { makerAssetAcquiredAmount,
_addFillResultsDeductFees(totalFillResults, singleFillResults); _safeSub(singleFillResults.makerAssetFilledAmount, singleFillResults.takerFeePaid)
} else {
_addFillResults(totalFillResults, singleFillResults);
remainingTakerAssetFillAmount = _safeSub(
remainingTakerAssetFillAmount,
singleFillResults.takerFeePaid
); );
} wethSpentAmount = _safeAdd(
remainingTakerAssetFillAmount = _safeSub( wethSpentAmount,
remainingTakerAssetFillAmount,
singleFillResults.takerAssetFilledAmount singleFillResults.takerAssetFilledAmount
); );
} else {
// We first sell WETH as the takerAsset, then use it to pay the takerFee.
// This ensures that we reserve enough to pay the fee.
uint256 takerAssetFillAmount = _getPartialAmountCeil(
orders[i].takerAssetAmount,
_safeAdd(orders[i].takerAssetAmount, orders[i].takerFee),
remainingTakerAssetFillAmount
);
singleFillResults = _fillOrderNoThrow(
orders[i],
takerAssetFillAmount,
signatures[i]
);
wethSpentAmount = _safeAdd(
wethSpentAmount,
_safeAdd(singleFillResults.takerAssetFilledAmount, singleFillResults.takerFeePaid)
);
makerAssetAcquiredAmount = _safeAdd(
makerAssetAcquiredAmount,
singleFillResults.makerAssetFilledAmount
);
}
_addFillResults(totalFillResults, singleFillResults);
// Stop execution if the entire amount of takerAsset has been sold // Stop execution if the entire amount of takerAsset has been sold
if (totalFillResults.takerAssetFilledAmount >= wethSellAmount) { if (wethSpentAmount >= wethSellAmount) {
break; break;
} }
} }
return totalFillResults; return (totalFillResults, wethSpentAmount, makerAssetAcquiredAmount);
} }
/// @dev Synchronously executes multiple fill orders in a single transaction until total amount is bought by taker. /// @dev Synchronously executes multiple fill orders in a single transaction until total amount is bought by taker.
@ -144,10 +174,13 @@ contract MixinExchangeWrapper is
bytes[] memory signatures bytes[] memory signatures
) )
internal internal
returns (FillResults memory totalFillResults) returns (
FillResults memory totalFillResults,
uint256 wethSpentAmount,
uint256 makerAssetAcquiredAmount
)
{ {
uint256 ordersLength = orders.length; uint256 ordersLength = orders.length;
uint256 makerAssetFilledAmount = 0;
for (uint256 i = 0; i != ordersLength; i++) { for (uint256 i = 0; i != ordersLength; i++) {
require( require(
@ -156,7 +189,7 @@ contract MixinExchangeWrapper is
); );
// Calculate the remaining amount of makerAsset to buy // Calculate the remaining amount of makerAsset to buy
uint256 remainingMakerAssetFillAmount = _safeSub(makerAssetFillAmount, totalFillResults.makerAssetFilledAmount); uint256 remainingMakerAssetFillAmount = _safeSub(makerAssetFillAmount, makerAssetAcquiredAmount);
// Convert the remaining amount of makerAsset to buy into remaining amount // Convert the remaining amount of makerAsset to buy into remaining amount
// of takerAsset to sell, assuming entire amount can be sold in the current order. // of takerAsset to sell, assuming entire amount can be sold in the current order.
@ -177,22 +210,36 @@ contract MixinExchangeWrapper is
// Update amounts filled and fees paid by maker and taker // Update amounts filled and fees paid by maker and taker
if (orders[i].makerAssetData.equals(orders[i].takerFeeAssetData)) { if (orders[i].makerAssetData.equals(orders[i].takerFeeAssetData)) {
_addFillResultsDeductFees(totalFillResults, singleFillResults); makerAssetAcquiredAmount = _safeAdd(
makerAssetAcquiredAmount,
_safeSub(singleFillResults.makerAssetFilledAmount, singleFillResults.takerFeePaid)
);
wethSpentAmount = _safeAdd(
wethSpentAmount,
singleFillResults.takerAssetFilledAmount
);
} else { } else {
_addFillResults(totalFillResults, singleFillResults); makerAssetAcquiredAmount = _safeAdd(
makerAssetAcquiredAmount,
_safeSub(singleFillResults.makerAssetFilledAmount, singleFillResults.takerFeePaid)
);
wethSpentAmount = _safeAdd(
wethSpentAmount,
singleFillResults.takerAssetFilledAmount
);
} }
_addFillResults(totalFillResults, singleFillResults);
// Stop execution if the entire amount of makerAsset has been bought // Stop execution if the entire amount of makerAsset has been bought
makerAssetFilledAmount = totalFillResults.makerAssetFilledAmount; if (makerAssetAcquiredAmount >= makerAssetFillAmount) {
if (makerAssetFilledAmount >= makerAssetFillAmount) {
break; break;
} }
} }
require( require(
makerAssetFilledAmount >= makerAssetFillAmount, makerAssetAcquiredAmount >= makerAssetFillAmount,
"COMPLETE_FILL_FAILED" "COMPLETE_FILL_FAILED"
); );
return totalFillResults; return (totalFillResults, wethSpentAmount, makerAssetAcquiredAmount);
} }
} }

View File

@ -88,7 +88,13 @@ contract MixinForwarderCore is
// Market sell 95% of WETH. // Market sell 95% of WETH.
// ZRX fees are payed with this contract's balance. // ZRX fees are payed with this contract's balance.
orderFillResults = _marketSellWeth( uint256 wethSpentAmount;
uint256 makerAssetAcquiredAmount;
(
orderFillResults,
wethSpentAmount,
makerAssetAcquiredAmount
) = _marketSellWeth(
orders, orders,
wethSellAmount, wethSellAmount,
signatures signatures
@ -97,7 +103,7 @@ contract MixinForwarderCore is
// Transfer feePercentage of total ETH spent on primary orders to feeRecipient. // Transfer feePercentage of total ETH spent on primary orders to feeRecipient.
// Refund remaining ETH to msg.sender. // Refund remaining ETH to msg.sender.
_transferEthFeeAndRefund( _transferEthFeeAndRefund(
orderFillResults.takerAssetFilledAmount, wethSpentAmount,
feePercentage, feePercentage,
feeRecipient feeRecipient
); );
@ -105,7 +111,7 @@ contract MixinForwarderCore is
// Transfer purchased assets to msg.sender. // Transfer purchased assets to msg.sender.
_transferAssetToSender( _transferAssetToSender(
orders[0].makerAssetData, orders[0].makerAssetData,
orderFillResults.makerAssetFilledAmount makerAssetAcquiredAmount
); );
} }
@ -136,7 +142,13 @@ contract MixinForwarderCore is
// Attempt to purchase desired amount of makerAsset. // Attempt to purchase desired amount of makerAsset.
// ZRX fees are payed with this contract's balance. // ZRX fees are payed with this contract's balance.
orderFillResults = _marketBuyExactAmountWithWeth( uint256 wethSpentAmount;
uint256 makerAssetAcquiredAmount;
(
orderFillResults,
wethSpentAmount,
makerAssetAcquiredAmount
) = _marketBuyExactAmountWithWeth(
orders, orders,
makerAssetFillAmount, makerAssetFillAmount,
signatures signatures
@ -145,7 +157,7 @@ contract MixinForwarderCore is
// Transfer feePercentage of total ETH spent on primary orders to feeRecipient. // Transfer feePercentage of total ETH spent on primary orders to feeRecipient.
// Refund remaining ETH to msg.sender. // Refund remaining ETH to msg.sender.
_transferEthFeeAndRefund( _transferEthFeeAndRefund(
orderFillResults.takerAssetFilledAmount, wethSpentAmount,
feePercentage, feePercentage,
feeRecipient feeRecipient
); );
@ -153,7 +165,7 @@ contract MixinForwarderCore is
// Transfer purchased assets to msg.sender. // Transfer purchased assets to msg.sender.
_transferAssetToSender( _transferAssetToSender(
orders[0].makerAssetData, orders[0].makerAssetData,
orderFillResults.makerAssetFilledAmount makerAssetAcquiredAmount
); );
} }
} }

View File

@ -402,19 +402,4 @@ library LibFillResults {
return matchedFillResults; return matchedFillResults;
} }
/// @dev Adds properties of both FillResults instances.
/// Modifies the first FillResults instance specified.
/// @param totalFillResults Fill results instance that will be added onto.
/// @param singleFillResults Fill results instance that will be added to totalFillResults.
function _addFillResultsDeductFees(FillResults memory totalFillResults, FillResults memory singleFillResults)
internal
pure
{
totalFillResults.makerAssetFilledAmount = _safeAdd(totalFillResults.makerAssetFilledAmount, singleFillResults.makerAssetFilledAmount);
totalFillResults.takerAssetFilledAmount = _safeAdd(totalFillResults.takerAssetFilledAmount, singleFillResults.takerAssetFilledAmount);
// The fee amount must be deducted from the amount transfered back to sender.
totalFillResults.makerAssetFilledAmount = _safeSub(totalFillResults.makerAssetFilledAmount, singleFillResults.takerFeePaid);
}
} }